<!DOCTYPE html>



  


<html class="theme-next muse use-motion" lang="zh-Hans">
<head><meta name="generator" content="Hexo 3.8.0">
  <meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<meta name="theme-color" content="#222">









<meta http-equiv="Cache-Control" content="no-transform">
<meta http-equiv="Cache-Control" content="no-siteapp">
















  
  
  <link href="/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css">







<link href="/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css">

<link href="/css/main.css?v=5.1.4" rel="stylesheet" type="text/css">


  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png?v=5.1.4">


  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png?v=5.1.4">


  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png?v=5.1.4">


  <link rel="mask-icon" href="/images/logo.svg?v=5.1.4" color="#222">





  <meta name="keywords" content="Hexo, NexT">





  <link rel="alternate" href="/atom.xml" title="renhao" type="application/atom+xml">






<meta name="description" content="本文总结 《HTTP 权威指南》的要点部分。">
<meta property="og:type" content="article">
<meta property="og:title" content="【读书笔记】HTTP 权威指南">
<meta property="og:url" content="https://huangrenhao.gitee.io/2020/09/28/read-http-the-definitive-guide/index.html">
<meta property="og:site_name" content="renhao">
<meta property="og:description" content="本文总结 《HTTP 权威指南》的要点部分。">
<meta property="og:locale" content="zh-Hans">
<meta property="og:image" content="https://huangrenhao.gitee.io/2020/09/28/read-http-the-definitive-guide/read-http-the-definitive-guide/relative-url-resolution-algorithm.png">
<meta property="og:image" content="https://huangrenhao.gitee.io/2020/09/28/read-http-the-definitive-guide/read-http-the-definitive-guide/ip-grouping.png">
<meta property="og:image" content="https://huangrenhao.gitee.io/2020/09/28/read-http-the-definitive-guide/read-http-the-definitive-guide/tcp-three-way-handshake.png">
<meta property="og:image" content="https://huangrenhao.gitee.io/2020/09/28/read-http-the-definitive-guide/read-http-the-definitive-guide/web-server-request-steps.png">
<meta property="og:image" content="https://huangrenhao.gitee.io/2020/09/28/read-http-the-definitive-guide/read-http-the-definitive-guide/no-proxy-uri-resolution.png">
<meta property="og:image" content="https://huangrenhao.gitee.io/2020/09/28/read-http-the-definitive-guide/read-http-the-definitive-guide/parsing-with-explicit-proxy-uri.png">
<meta property="og:image" content="https://huangrenhao.gitee.io/2020/09/28/read-http-the-definitive-guide/read-http-the-definitive-guide/has-interception-proxy-uri-resolution.png">
<meta property="og:updated_time" content="2020-10-13T07:37:31.000Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="【读书笔记】HTTP 权威指南">
<meta name="twitter:description" content="本文总结 《HTTP 权威指南》的要点部分。">
<meta name="twitter:image" content="https://huangrenhao.gitee.io/2020/09/28/read-http-the-definitive-guide/read-http-the-definitive-guide/relative-url-resolution-algorithm.png">



<script type="text/javascript" id="hexo.configurations">
  var NexT = window.NexT || {};
  var CONFIG = {
    root: '/',
    scheme: 'Muse',
    version: '5.1.4',
    sidebar: {"position":"left","display":"post","offset":12,"b2t":false,"scrollpercent":false,"onmobile":false},
    fancybox: true,
    tabs: true,
    motion: {"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},
    duoshuo: {
      userId: '0',
      author: '博主'
    },
    algolia: {
      applicationID: '',
      apiKey: '',
      indexName: '',
      hits: {"per_page":10},
      labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
    }
  };
</script>



  <link rel="canonical" href="https://huangrenhao.gitee.io/2020/09/28/read-http-the-definitive-guide/">





  <title>【读书笔记】HTTP 权威指南 | renhao</title>
  








<link rel="stylesheet" href="/css/prism-tomorrow.css" type="text/css"></head>

<body itemscope="" itemtype="http://schema.org/WebPage" lang="zh-Hans">
  
  
    
  

  <div class="container sidebar-position-left page-post-detail">
    <div class="headband"></div>

    <header id="header" class="header" itemscope="" itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-wrapper">
  <div class="site-meta ">
    

    <div class="custom-logo-site-title">
      <a href="/" class="brand" rel="start">
        <span class="logo-line-before"><i></i></span>
        <span class="site-title">renhao</span>
        <span class="logo-line-after"><i></i></span>
      </a>
    </div>
      
        <p class="site-subtitle"></p>
      
  </div>

  <div class="site-nav-toggle">
    <button>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
    </button>
  </div>
</div>

<nav class="site-nav">
  

  
    <ul id="menu" class="menu">
      
        
        <li class="menu-item menu-item-home">
          <a href="/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-home"></i> <br>
            
            首页
          </a>
        </li>
      
        
        <li class="menu-item menu-item-categories">
          <a href="/categories/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-th"></i> <br>
            
            分类
          </a>
        </li>
      
        
        <li class="menu-item menu-item-archives">
          <a href="/archives/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-archive"></i> <br>
            
            归档
          </a>
        </li>
      

      
    </ul>
  

  
</nav>



 </div>
    </header>

    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          <div id="content" class="content">
            

  <div id="posts" class="posts-expand">
    

  

  
  
  

  <article class="post post-type-normal" itemscope="" itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="https://huangrenhao.gitee.io/2020/09/28/read-http-the-definitive-guide/">

    <span hidden itemprop="author" itemscope="" itemtype="http://schema.org/Person">
      <meta itemprop="name" content="renhao">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope="" itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="renhao">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">【读书笔记】HTTP 权威指南</h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2020-09-28T10:54:34+08:00">
                2020-09-28
              </time>
            

            

            
          </span>

          
            <span class="post-category">
            
              <span class="post-meta-divider">|</span>
            
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              
                <span class="post-meta-item-text">分类于</span>
              
              
                <span itemprop="about" itemscope="" itemtype="http://schema.org/Thing">
                  <a href="/categories/读书笔记/" itemprop="url" rel="index">
                    <span itemprop="name">读书笔记</span>
                  </a>
                </span>

                
                
              
            </span>
          

          
            
              <span class="post-comments-count">
                <span class="post-meta-divider">|</span>
                <span class="post-meta-item-icon">
                  <i class="fa fa-comment-o"></i>
                </span>
                <a href="/2020/09/28/read-http-the-definitive-guide/#comments" itemprop="discussionUrl">
                  <span class="post-comments-count valine-comment-count" data-xid="/2020/09/28/read-http-the-definitive-guide/" itemprop="commentCount"></span>
                </a>
              </span>
            
          

          
          

          

          
            <div class="post-wordcount">
              
                
                <span class="post-meta-item-icon">
                  <i class="fa fa-file-word-o"></i>
                </span>
                
                  <span class="post-meta-item-text">字数统计&#58;</span>
                
                <span title="字数统计">
                  27.1k
                </span>
              

              
                <span class="post-meta-divider">|</span>
              

              
                <span class="post-meta-item-icon">
                  <i class="fa fa-clock-o"></i>
                </span>
                
                  <span class="post-meta-item-text">阅读时长 &asymp;</span>
                
                <span title="阅读时长">
                  94
                </span>
              
            </div>
          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        <p>本文总结 《HTTP 权威指南》的要点部分。<a id="more"></a></p>
<h2 id="第2章-URL与资源"><a href="#第2章-URL与资源" class="headerlink" title="第2章 URL与资源"></a>第2章 URL与资源</h2><h3 id="媒体类型"><a href="#媒体类型" class="headerlink" title="媒体类型"></a>媒体类型</h3><p>web服务器会为所有HTTP对象数据附加一个MIME类型，浏览器可以根据MIME类型知道如何处理这个对象。</p>
<p>常见：</p>
<ul>
<li>text/html : HTML格式文本文档</li>
<li>text/plain：普通ASCII文本文档</li>
<li>image/jpeg : jpeg图片</li>
<li>image/gif : gif图片</li>
<li>video ： Apple的QuickTime电影</li>
<li>application/vnd.ms-powerpoint : 微软的PowerPoint演示文件</li>
</ul>
<h3 id="URI"><a href="#URI" class="headerlink" title="URI"></a>URI</h3><p>URI：统一资源标志符（Uniform Resource Identifier），在世界范围内唯一标识并定位信息资源。有两种形式URL和URN。</p>
<p>URN：统一资源名，用特定名称定位资源，与资源所在地无关，仍处于实验阶段。</p>
<h3 id="URL"><a href="#URL" class="headerlink" title="URL"></a>URL</h3><p>URL，统一资源定位符，通过描述资源的位置来定位资源。</p>
<h4 id="通用格式"><a href="#通用格式" class="headerlink" title="通用格式"></a>通用格式</h4><p><code>&lt;scheme&gt;://&lt;user&gt;:&lt;password&gt;@&lt;host&gt;:&lt;port&gt;/&lt;path&gt;;&lt;params&gt;?&lt;query&gt;#&lt;frag&gt;</code></p>

<table>
    <th width="20%">组件</th>
    <th width="60%">描述</th>
    <th width="20%">默认值</th>
    <tr>
        <td>方案</td>
        <td>访问服务器以获取资源时要使用哪种协议</td>
        <td>无</td>
    </tr>
    <tr>
    	<td>用户</td>
        <td>某些方案访问资源时需要的用户名</td>
        <td>匿名</td>
    </tr>
    <tr>
    	<td>密码</td>
        <td>用户名后面可能要包含的密码，中间由冒号（:）分隔</td>
        <td>&lt;E-mail地址&gt;</td>
    </tr>
    <tr>
    	<td>主机</td>
        <td>资源宿主服务器的主机名或点分IP地址</td>
        <td>无</td>
    </tr>
    <tr>
    	<td>端口</td>
        <td>资源宿主服务器正在监听的端口号</td>
        <td>每个方案特有</td>
    </tr>
    <tr>
    	<td>路径</td>
        <td>服务器上资源的本地名</td>
        <td>无</td>
    </tr>
	<tr>
    	<td>参数</td>
        <td>某些方案会用这个组件来指定输入参数。参数为名/值对时可以包含多个参数字段，相互之间以及与路径的其余部分之间以分号间隔</td>
        <td>无</td>
    </tr>
    <tr>
    	<td>查询</td>
        <td>某些方案会用这个组件传递参数以激活应用程序（如数据库、搜索引擎以及其他因特网网关），查询组件的内容没有通用格式。用“？”将其与URL其余部分分隔开</td>
        <td>无</td>
    </tr>
    <tr>
    	<td>片段</td>
        <td>一小片或一部分资源的名字，通过字符“#”将其与URL的其余部分分隔开</td>
        <td>无</td>
    </tr>
</table>

<p>方案组件必须以一个字母符号开始，由第一个“：”符号将其与URL的其余部分分隔开，方案名大小写无关。</p>
<p>主机组件可以用主机名或者IP地址来表示宿主机器。</p>
<p>URL方案要求输入用户名和密码（比如FTP）但没有提供的话就是插入<code>anonymous</code>（匿名用户）作为用户名，发送一个默认的密码。</p>
<p>参数组件是为了向应用程序提供它们所需的输入参数，以便能正确地与服务器进行交互。例如FTP有二进制和文本两种形式的传输模式，这个时候就需要指定参数避免以文本形式来传送二进制图片。URL路径的每个路径段都可以有自己的参数。</p>
<p>URL的查询组件和标志网关资源的URL路径组件一起被发送给网关资源，按照常规查询字符串以一系列“名/值”对的形式出现，名值对之间用字符“&amp;”分隔。</p>
<p>HTTP服务器通常只处理整个对象而不是对象的片段，浏览器从服务器获得了整个资源之后，会根据片段来显示。</p>
<h4 id="相对URL解析"><a href="#相对URL解析" class="headerlink" title="相对URL解析"></a>相对URL解析</h4><p><img src="./read-http-the-definitive-guide/relative-url-resolution-algorithm.png" alt="相对URL解析算法" style="zoom:50%;"></p>
<h4 id="URL的自动扩展"><a href="#URL的自动扩展" class="headerlink" title="URL的自动扩展"></a>URL的自动扩展</h4><ul>
<li>主机名扩展：输入<code>yahoo</code>，浏览器自动插入<code>www.</code>和<code>.com</code>。</li>
<li>历史扩展：历史输入的URL填充建议。</li>
</ul>
<h3 id="URL编码机制和字符限制"><a href="#URL编码机制和字符限制" class="headerlink" title="URL编码机制和字符限制"></a>URL编码机制和字符限制</h3><p>编码机制：通过“转义”表示法来表示不安全的字符，包含一个百分号（%），后面跟着两个表示字符ASCII码的十六进制数。</p>
<p>空格的ASCII码为32（0x20），在URL中表示为<code>%20</code>；百分号%的ASCII码为37（0x25)，在URL中表示为<code>%25</code>；波浪符号~的ASCII码为126（0x7E），在URL中表示为<code>%7E</code>。</p>
<h2 id="第3章-HTTP报文"><a href="#第3章-HTTP报文" class="headerlink" title="第3章 HTTP报文"></a>第3章 HTTP报文</h2><h3 id="报文流"><a href="#报文流" class="headerlink" title="报文流"></a>报文流</h3><p>HTTP报文指HTTP应用程序之间发送的数据块，以文本形式的元信息开头（描述报文的内容和含义），后面是可选的数据部分。</p>
<p>“流入”、“流出”、“上游”、“下游”：用来描述报文方向的术语。流入（流向服务器），流出（流向用户Agent代理或者用户客户端），所有报文的发送者都在接收者的上游，即所有报文都会向下游流动。</p>
<h3 id="报文的组成部分"><a href="#报文的组成部分" class="headerlink" title="报文的组成部分"></a>报文的组成部分</h3><p>由三个部分组成：对报文进行描述的起始行、包含属性的首部块、可选的包含数据的主体部分。</p>
<p>起始行和首部是由行分隔的ASCII文本，每行以行终止序列CRLF（回车换行\r\n）作为结束。主体可以包含文本、二进制数据或者为空。首部中Content-Type说明主体的内容类型，Content-Length说明主体内容的大小。</p>
<h4 id="报文语法"><a href="#报文语法" class="headerlink" title="报文语法"></a>报文语法</h4><p>所有HTTP报文可以分为：请求报文和响应报文</p>
<p>请求报文：</p>
<pre><code>&lt;method&gt;&lt;request-URL&gt;&lt;version&gt;
&lt;headers&gt;

&lt;entity-body&gt;
</code></pre><p>响应报文：</p>
<pre><code>&lt;version&gt;&lt;status&gt;&lt;reason-phrase&gt;
&lt;headers&gt;

&lt;entity-body&gt;
</code></pre><p>首部是以一个空行（单个CRLF）结束，表示首部列表的结束和实体主体部分的开始。</p>
<h4 id="起始行"><a href="#起始行" class="headerlink" title="起始行"></a>起始行</h4><p>请求报文的起始行称为请求行，请求行中method描述了服务器应该执行的操作，request-URL描述了要对哪个资源执行这个方法，version用来告知服务器客户端使用的是哪种HTTP，这三个字段以空格符分隔。</p>
<p>method（方法）：</p>
<ul>
<li><strong>GET</strong>，请求服务器发送某个资源。</li>
<li><strong>HEAD</strong>，与GET方法行为类似，但服务器在响应中只返回首部，不会返回实体的主体部分。可以在不获取资源的情况下了解资源的情况（比如判断类型），通过响应中的状态码判断对象是否存在，通过首部判断资源是否被修改。</li>
<li><strong>PUT</strong>，让服务器用请求的主体部分来创建一个由所请求的URL命名的新文档（如果URL存在则替换），很多web服务器都需要执行put之前进行密码登录</li>
<li><strong>POST</strong>，向服务器输入数据，可以用来支持HTML的表单。POST与PUT的区别在于POST用于向服务器发送数据，PUT用于向服务器上的资源中存储数据。</li>
<li><strong>TRACE</strong>，在目的服务器端发起一个“环回”诊断，行程最后一站的服务器会弹回一条TRACE响应，响应主体中携带它收到的原始请求报文，客户端接收到这个报文就可查看所有中间HTTP应用程序组成的请求/响应链上原始报文是否以及如何被毁坏或者修改。TRACE请求中不能带有实体的主体部分。假定条件是中间应用程序对各种不同类型请求（GET、HEAD、POST等）的处理是相同的（代理可能将POST请求发送给服务器，而将GET请求发送给Web缓存），并不提供区分这些方法的机制，中间应用程序自行决定如何处理TRACE请求。</li>
<li><strong>OPTIONS</strong>，可以询问服务器通常支持哪些方法或者对某些特殊资源支持哪些方法。</li>
<li><strong>DELETE</strong>，请服务器删除请求URL所指定的资源（HTTP规范允许服务器在不通知客户端的情况下撤销请求）。</li>
<li>扩展方法：没有在HTTP/1.1规范中定义的方法，可能会被HTTP应用程序所不理解，如LOCK、MKCOL、COPY、MOVE等WebDAV HTTP扩展将在之后介绍。</li>
</ul>
<p>响应报文的起始行称为响应行，包含响应报文使用的HTTP版本、数字状态码以及描述操作状态的文本形式的原因状语，所有这些字段由空格符进行分隔。</p>
<p>status（状态码）：</p>
<ul>
<li><p>100~199信息性状态码</p>

  <table>
      <th>状态码</th>
      <th>原因短语</th>
      <th>含义</th>
      <tr>
      	<td>100</td>
          <td>Continue</td>
          <td>说明收到了请求的初始部分，请客户端继续。发送了这个状态码之后，服务器在收到请求之后必须进行响应</td>
      </tr>
      <tr>
      	<td>101</td>
          <td>Switching Protocols</td>
          <td>说明服务器正在根据客户端的指定，将协议切换成Update首部所列的协议</td>
      </tr>
  </table>
  
</li>
</ul>
<p>  100 Continue状态是对HTTP客户端应用程序有一个实体的主体部分要发送给服务器但希望在发送之前查看一下服务器是否会接受这个实体的情况下进行优化，可以避免客户端向服务器发送一个服务器无法处理或使用的大实体。客户端在向服务器发送一个实体，并且愿意在发送实体之前等待100 Continue响应，客户端就发送一个携带了值为100 Continue的Expect请求首部（告知服务器它们需求某种行为），客户端在超时一定时间后没有收到100 Continue响应会直接将实体发送出去。服务器在收到一条带有值为100 Continue的Expect首部请求会用100 Continue响应或者一条错误码响应（服务器不应该向没有发送100 Continue期望的客户端发送100 Continue状态码），如果在发送100 Continue之前就收到了部分实体就不需要发送这个状态码但在读完请求后发送一个最终状态码。代理接收到客户端发送的100 Continue期望请求会根据下一跳服务器HTTP版本的兼容情况（信息性状态码在HTTP/1.1中引入），如果得知下一跳服务器只能与HTTP/1.1之前的版本兼容就以417错误状态码响应，否则都应该将Expect首部放在请求中向下转发。如果代理决定代表与HTTP/1.0或之前版本兼容的客户端，在其请求中放入Expect首部和100 Continue值，如果它从服务器收到了100 Continue响应就不应该将100 Continue响应转发给客户端（客户端可能不知道如何处理）。</p>
<ul>
<li><p>200~299成功状态码</p>

  <table>
      <th>状态码</th>
      <th>原因短语</th>
      <th>含义</th>
      <tr>
      	<td>200</td>
          <td>OK</td>
          <td>请求没问题，实体的主体部分包含了所请求的资源</td>
      </tr>
      <tr>
      	<td>201</td>
          <td>Created</td>
          <td>用于创建服务器对象的请求（如PUT），响应的实体主体部分中应该包含各种引用了已创建的资源URL，Location首部包含的则是最具体的引用，服务器在发送这个状态码之前必须创建好对象</td>
      </tr>
      <tr>
      	<td>202</td>
          <td>Accepted</td>
          <td>请求已被接受，但是服务器还未对其执行任何动作，不能保证服务器会完成这个请求，服务器应该在实体的主体部分包含对请求状态的描述，可能有对请求完成时间的估计或者一个指向可以获取此信息位置的指针</td>
      </tr>
      <tr>
      	<td>203</td>
          <td>Non-Authoritative-Information</td>
          <td>实体首部包含的信息来自资源的一份副本（而不是源端服务器），如果中间节点上有一份资源副本但无法或者没有对它所发送的与资源有关的元信息（首部）进行验证出现这种情况。</td>
      </tr>
      <tr>
      	<td>204</td>
      	<td>No Content</td>
      	<td>响应报文中包含若干首部和一个状态行，但没有实体主体部分。用于在浏览器不转为显示新文档的情况下对其进行更新（比如刷新一个表单页面）</td>
      </tr>
      <tr>
      	<td>205</td>
          <td>Reset Content</td>
          <td>负责告知浏览器清除当前页面中所有HTML表单元素</td>
      </tr>
      <tr>
      	<td>206</td>
          <td>Partial Content</td>
          <td>成功执行了一个部分或者Range请求（对客户端通过特殊首部来获取部分或者某个范围内的文档说明成功执行），响应中必须包含Content-Range、Date以及ETag或Content-Location首部</td>
      </tr>
  </table>
  
</li>
<li><p>300~399重定向状态码</p>

  <table>
      <th>状态码</th>
      <th>原因短语</th>
      <th>含义</th>
      <tr>
      	<td>300</td>
          <td>Multiple Choices</td>
          <td>客户端请求一个实际指向多个资源的URL时会返回这个状态码和一个选项列表，服务器可以在Location首部中包含首选URL</td>
      </tr>
      <tr>
      	<td>301</td>
          <td>Moved Permanently</td>
          <td>在请求的URL已被移除时使用，响应中Location中应该包含资源现在的URL</td>
      </tr>
      <tr>
      	<td>302</td>
          <td>Found</td>
          <td>在请求的URL已被移除时使用，客户端使用Location首部给出的URL来临时定位资源，将来请求仍用老URL</td>
      </tr>
      <tr>
      	<td>303</td>
          <td>See Other</td>
          <td>告知客户端应该用另一个URL来获取资源，响应中Location首部给出新URL，主要目的是允许POST请求的响应将客户端定向到某个资源上去</td>
      </tr>
      <tr>
      	<td>304</td>
          <td>Not Modified</td>
          <td>客户端可以通过所包含的请求首部，使其请求变成有条件的，如果客户端发起了一个条件GET请求而最近资源未被修改的情况下就可以用这个状态码说明资源未被修改，带有这个状态码的响应不应该包含实体的主体部分</td>
      </tr>
      <tr>
      	<td>305</td>
          <td>Use Proxy</td>
          <td>用来说明必须通过一个代理访问资源，代理位置由Location首部给出，只是针对特定的资源，不能假定所有请求都通过代理</td>
      </tr>
      <tr>
      	<td>307</td>
          <td>Temporary Redirect</td>
          <td>与302相同</td>
      </tr>
  </table>
  
</li>
</ul>
<p>  状态码之间的存在交叉或者用法之间存在细微差别源于HTTP/1.0和HTTP/1.1应用程序对这些状态码处理方式不同。</p>
<p>  如这里的302、303、307：如果 HTTP/1.0 服务器收到来自 HTTP/1.0 客户端的 POST 请求之后发送了 302 状态码，服务器就期望客户端能够接收重定向 URL ，并向重定向的 URL 发送一个 GET 请求（POST 请求非幂等）。HTTP/1.1 规范中使用 303 状态码来实现同样的行为（服务器发送 303 状态码来重定向客户端的 POST 请求，在它后面跟上一个 GET 请求），HTTP/1.1 规范又指出对于 HTTP/1.1 客户端用 307 状态码取代 302 状态码来进行临时重定向。</p>
<p>  重定向使用情况分类：</p>
<ul>
<li>永久删除的资源：资源被移动到新的位置、重新命名，有新的URL。状态码301</li>
<li>临时删除的资源：资源被临时移走或重命名，暂时重定向。状态码303、307</li>
<li>URL增强：重定向生成一个新的包含了嵌入式状态信息的URL（下次请求为完整的、经过状态增强的URL），在事务间维持状态。状态码303、307</li>
<li>负载均衡：服务器超载重定向到负载不重的服务器。状态码303、307</li>
<li>服务器关联：服务器上可能或有某些用户的本地信息，可以将客户端重定向到包含了该信息的服务器上。状态码303、307</li>
<li>规范目录名称：请求URI是一个不带尾部斜线的目录名，可以将其重定向到一个加了斜线的URI上，这样相对连接可以正常工作</li>
</ul>
<ul>
<li><p>400~499客户端错误状态码</p>

  <table>
      <th>状态码</th>
      <th>原因短语</th>
      <th>含义</th>
      <tr>
      	<td>400</td>
          <td>Bad Request</td>
          <td>告知客户端它发送了一个错误的请求</td>
      </tr>
      <tr>
      	<td>401</td>
          <td>Unauthorized</td>
          <td>与适当的首部一同返回，在这些首部中请求客户端在获取对资源的访问权之前，对自己进行认证</td>
      </tr>
      <tr>
      	<td>403</td>
          <td>Forbidden</td>
          <td>请求被服务器拒绝，原因可能包含在实体的主体部分（但这个状态码通常使用在服务器不想说明拒绝原因的情况下使用）</td>
      </tr>
      <tr>
      	<td>404</td>
          <td>Not Found</td>
          <td>服务器无法找到所请求的URL，通常实体内容用于客户端显示给用户看</td>
      </tr>
      <tr>
      	<td>405</td>
          <td>Method Not Allowed</td>
          <td>请求中的方法不被请求中的URL支持，响应中应该包含Allow首部告知客户端可以对所请求资源使用的方法</td>
      </tr>
      <tr>
      	<td>406</td>
          <td>Not Acceptable</td>
          <td>客户端可以指定参数说明愿意接收什么类型的实体，服务器没有与客户端可接受的URL相匹配的资源使用这个状态码。通常首部会给出为什么请求无法满足</td>
      </tr>
      <tr>
      	<td>407</td>
          <td>Proxy Authentication</td>
          <td>与401状态码类似，但用于要求对资源进行认证的代理服务器</td>
      </tr>
      <tr>
      	<td>408</td>
          <td>Request Timeout</td>
          <td>客户端完成请求所花的时间太长，回送此状态码并关闭连接，超时时长随服务器不同而不同</td>
      </tr>
      <tr>
      	<td>409</td>
          <td>Conflict</td>
          <td>请求可能在资源上引发一些冲突，响应中应该包含描述冲突的主体</td>
      </tr>
      <tr>
      	<td>410</td>
          <td>Gone</td>
          <td>与404类似，服务器曾经拥有过此资源</td>
      </tr>
      <tr>
      	<td>411</td>
          <td>Length Required</td>
          <td>服务器要求在请求报文中包含Content-Length首部</td>
      </tr>
      <tr>
      	<td>412</td>
          <td>Precondition Failed</td>
          <td>客户端发起条件请求（包含Expect首部）其中一个条件失败的时候使用</td>
      </tr>
      <tr>
      	<td>413</td>
          <td>Request Entity Too Large</td>
          <td>客户端发送的实体主体部分比服务器能够活着希望处理的要大</td>
      </tr>
      <tr>
      	<td>414</td>
          <td>Request URL Too Long</td>
          <td>请求中请求URL比服务器能够或者希望处理的要长</td>
      </tr>
      <tr>
      	<td>415</td>
          <td>Unsupported Media Type</td>
          <td>服务器无法理解或无法支持客户端所发实体的内容类型</td>
      </tr>
      <tr>
      	<td>416</td>
          <td>Request Range Not Satisfiable</td>
          <td>请求报文请求的是指定资源的某个范围但此范围无效或者无法满足</td>
      </tr>
      <tr>
      	<td>417</td>
          <td>Expectation Failed</td>
          <td>请求的Expect首部包含了一个期望，服务器无法满足此期望，如果代理或其他中间应用程序肯定源端服务器会为某请求产生一个失败的期望就可以发送这个状态码</td>
      </tr>
  </table>
  
</li>
<li><p>500~599服务器错误状态码</p>

  <table>
      <th>状态码</th>
      <th>原因短语</th>
      <th>含义</th>
      <tr>
      	<td>500</td>
          <td>Internal Server Error</td>
          <td>服务器遇到一个妨碍它为请求提供服务的错误</td>
      </tr>
      <tr>
      	<td>501</td>
          <td>Not Implemented</td>
          <td>请求超出服务器的能力范围（比如服务器不支持的请求方法）</td>
      </tr>
      <tr>
     		<td>502</td> 
          <td>Bad Gateway</td>
          <td>作为代理或者网关使用的服务器从请求响应链的下一条链路上收到了一条伪响应（比如无法连接到父网关）</td>
      </tr>
      <tr>
      	<td>503</td>
          <td>Service Unavailable</td>
          <td>服务器现在无法为请求提供服务但将来可以，响应中可以包含一个Retry-After首部表明服务器可以提供服务的时间</td>
      </tr>
      <tr>
      	<td>504</td>
          <td>Gateway Timeout</td>
          <td>与408类似，这里的响应来自一个网关或代理，它们在等待另一服务器对其请求进行响应时超时</td>
      </tr>
      <tr>
      	<td>505</td>
          <td>HTTP Version Not Supported</td>
          <td>请求中的协议版本服务器无法或不愿支持</td>
      </tr>
  </table>
  
</li>
</ul>
<h4 id="首部"><a href="#首部" class="headerlink" title="首部"></a>首部</h4><ol>
<li><p>通用首部</p>
<p>提供与报文相关的最基本的信息</p>
<ul>
<li><p>通用的信息性首部</p>
<p>| 首部              | 描述                                                         |<br>| —————– | ———————————————————— |<br>| Connection        | 允许客户端和服务器指定与请求/响应连接有关的选项              |<br>| Date              | 提供日期和时间标志（说明报文创建时间）                       |<br>| MIME-Version      | 给出发送端使用的MIME类型                                     |<br>| Trailer           | 当报文采用分块传输编码方式可以用来列出位于报文拖挂部分的首部集合 |<br>| Transfer-Encoding | 告知接收端为了保证报文的可靠传输对报文采用的编码方式         |<br>| Update            | 给出发送端可能想要“升级”使用的新版本或协议                   |<br>| Via               | 显示报文经过的中间节点（代理、网关）                         |</p>
</li>
<li><p>通用缓存首部</p>
<p>| 首部          | 描述                                                         |<br>| ————- | ———————————————————— |<br>| Catch-Control | 用于随报文传送缓存首部                                       |<br>| Pragma        | 另一种随报文传送指示的方式（劣于Catch-Control），但并不专用于缓存 |</p>
</li>
</ul>
</li>
<li><p>请求首部</p>
<p>只在请求报文中有意义的首部</p>
<ul>
<li><p>请求的信息性首部</p>
<p>| 首部       | 描述                                   |<br>| ———- | ————————————– |<br>| Client-IP  | 提供运行客户端的机器的IP地址           |<br>| From       | 提供客户端用户的E-mail地址             |<br>| Host       | 给出接受请求的服务器的主机名和端口号   |<br>| Referer    | 提供包含当前请求URL的文档的URL         |<br>| UA-Color   | 与客户端显示器的显示颜色有关信息       |<br>| UA-CPU     | 客户端CPU类型或制造商                  |<br>| UA-Disp    | 客户端显示器（屏幕）能力有关信息       |<br>| UA-OS      | 运行在客户端机器上的操作系统名称及版本 |<br>| UA-Pixels  | 客户端显示器的像素信息                 |<br>| User-Agent | 将发起请求的应用程序名称告知服务器     |</p>
</li>
<li><p>Accept首部</p>
<p>为客户端提供了一种将其喜好和能力告知服务器的方式，这样客户端可以得到它们想要的内容，服务器则不会浪费其时间和带宽来发送客户端无法使用的东西</p>
<p>| 首部            | 描述                               |<br>| ————— | ———————————- |<br>| Accept          | 告诉服务器能够发送哪些媒体类型     |<br>| Accept-Charset  | 告诉服务器能够发送哪些字符集       |<br>| Accept-Encoding | 告诉服务器能够发送哪些编码方式     |<br>| Accept-Language | 告诉服务器能够发送哪些语言         |<br>| TE              | 告诉服务器可以使用哪些扩展传输编码 |</p>
</li>
<li><p>条件请求首部</p>
<p>对请求加上某些限制，要求服务器在对请求进行响应之前确保某个条件为真</p>
<p>| 首部                | 描述                                                       |<br>| ——————- | ———————————————————- |<br>| Expect              | 允许客户端列出某请求所要求的服务器行为                     |<br>| If-Match            | 如果实体标记与文档当前的实体标记相匹配则获取这份文档       |<br>| If-Modified-Since   | 除非在某个指定的日期之后资源被修改过，否则限制这个请求     |<br>| If-None-Match       | 如果实体标记与文档当前的实体标记不匹配则获取这份文档       |<br>| If-Range            | 允许对文档的某个范围进行条件请求                           |<br>| If-Unmodified-Since | 除非在某个指定的日期之后资源没有被修改过，否则限制这个请求 |<br>| Range               | 如果服务器支持范围请求，就请求资源的指定范围               |</p>
</li>
<li><p>安全请求首部</p>
<p>| 首部          | 描述                                                         |<br>| ————- | ———————————————————— |<br>| Authorization | 包含了客户端提供给服务器以便对其自身进行认证的数据           |<br>| Cookie        | 客户端用它向服务器发送一个令牌（并不是真正的安全首部但隐含了安全功能） |<br>| Cookie2       | 用来说明请求端支持的cookie版本                               |</p>
</li>
<li><p>代理请求首部</p>
<p>| 首部                | 描述                                                         |<br>| ——————- | ———————————————————— |<br>| Max-Forward         | 在通往源端服务器的路径上将请求转发给其他代理或网关的最大次数（与TRACE方法一同使用） |<br>| Proxy-Authorization | 与Authorization首部相同，但这个首部在与代理认证使用          |<br>| Proxy-Connection    | 与Connection首部相同，在与代理建立连接时使用                 |</p>
</li>
</ul>
</li>
<li><p>响应首部</p>
<ul>
<li><p>响应的信息性首部</p>
<p>| 首部        | 描述                               |<br>| ———– | ———————————- |<br>| Age         | 响应持续时间（从最初创建开始）     |<br>| Public      | 服务器为其资源支持的请求方法列表   |<br>| Retry-After | 如果资源不可用，在此日期或时间重试 |<br>| Server      | 服务器应用程序软件的名称和版本     |<br>| Title       | HTML文档的源端给出的标题           |<br>| Warning     | 比原因短语中更详细一点的警告报文   |</p>
</li>
<li><p>协商首部</p>
<p>| 首部          | 描述                                                         |<br>| ————- | ———————————————————— |<br>| Accept-Ranges | 对此资源来说服务器可接受的范围类型                           |<br>| Vary          | 一个首部列表，服务器会根据这些首部内容挑选出最合适的资源版本发送给客户端 |</p>
</li>
<li><p>安全响应首部</p>
<p>| 首部               | 描述                                                         |<br>| —————— | ———————————————————— |<br>| Proxy-Authenticate | 来自代理的对客户端的质询列表                                 |<br>| Set-Cookie         | 在客户端设置一个令牌以便服务器对客户端进行标识（不是真正安全首部但隐含安全功能） |<br>| WWW-Authenticate   | 来自服务器的对客户端的质询列表                               |</p>
</li>
</ul>
</li>
</ol>
<ol start="4">
<li><p>实体首部</p>
<ul>
<li><p>实体的信息性首部</p>
<p>| 首部     | 描述                                                         |<br>| ——– | ———————————————————— |<br>| Allow    | 列出可以对此实体执行的请求方法                               |<br>| Location | 告知客户端实体实际上位于何处，用于将接收端定向到资源的位置上去 |</p>
</li>
<li><p>内容首部</p>
<p>| 首部             | 描述                               |<br>| —————- | ———————————- |<br>| Content-Base     | 解析主体中的相对URL时使用的基础URL |<br>| Content-Encoding | 对主体执行的任意编码方式           |<br>| Content-Language | 理解主体是最适宜使用的自然语言     |<br>| Content-Length   | 主体的长度或尺寸                   |<br>| Content-Location | 资源实际所处的位置                 |<br>| Content-MD5      | 主体的MD5校验和                    |<br>| Content-Range    | 在整个资源中此实体表示的字节范围   |<br>| Content-Type     | 这个主题的对象类型                 |</p>
</li>
<li><p>实体缓存首部</p>
<p>| 首部          | 描述                                                   |<br>| ————- | —————————————————— |<br>| ETag          | 与此实体相关的实体标记                                 |<br>| Expires       | 实体不再有效，要从原始的源端在此获取次实体的日期和时间 |<br>| Last-Modified | 这个实体最后一次被修改的日期和时间                     |</p>
</li>
</ul>
</li>
</ol>
<h4 id="实体"><a href="#实体" class="headerlink" title="实体"></a>实体</h4><p>可选的实体主体部分，HTTP报文的负荷即HTTP要传输的内容，如图片、视频、HTML文档等等。</p>
<p>HTTP/0.9报文也由请求和响应组成，但请求中只包含方法和请求URL，响应中只有实体。没有版本信息、状态码、原因短语、首部。</p>
<h2 id="第4章-连接管理"><a href="#第4章-连接管理" class="headerlink" title="第4章 连接管理"></a>第4章 连接管理</h2><h3 id="TCP连接"><a href="#TCP连接" class="headerlink" title="TCP连接"></a>TCP连接</h3><p>TCP为HTTP提供一条可靠的比特传输管道，从TCP连接一端填入的字节会从另一端以原有的顺序、正确地传送出来。</p>
<p>TCP的数据是通过IP分组（或IP数据报）的小数据块来发送，每个IP分组中都包括一个IP分组首部（通常为20字节）、一个TCP段首部（通常为20字节）、一个TCP数据块（0个或多个字节）。IP首部中包含了源和目的IP地址、长度和其他一些标记。TCP段的首部包含了TCP端口号、TCP控制标记，以及用于数据排序和完整性检查的一些数字值。</p>
<p><img src="./read-http-the-definitive-guide/ip-grouping.png" alt="IP分组" style="zoom:50%;"></p>
<p>任意时刻计算机都可以有几条TCP连接处于打开状态，TCP是通过端口号来保持所有这些连接的正确运行，IP地址可以保证连接到正确的计算机，端口号则可以连接到正确的应用程序上去。TCP连接是通过4个值来识别的：&lt;源IP地址、源端口号、目的IP地址、目的端口号&gt;，这4个值一起唯一地定义了一条连接，两条不同的TCP连接不能拥有4个完全相同的地址组件值（即不同连接的部分组件可以拥有相同的值）。</p>
<h3 id="TCP性能"><a href="#TCP性能" class="headerlink" title="TCP性能"></a>TCP性能</h3><p>HTTP事务时延包括DNS查询、TCP连接建立时延、请求报文的传输和处理、响应报文的传送，HTTP事务处理时间相对较短（除非客户端或服务器超载或正在处理复杂的动态资源，否则HTTP时延就是由TCP网络时延构成）。</p>
<p>TCP相关时延包括TCP连接建立握手、TCP慢启动拥塞控制、数据聚集的Nagle算法、用于捎带确认的TCP延迟确认算法、TIME_WAIT时延和端口耗尽。</p>
<h4 id="三次握手"><a href="#三次握手" class="headerlink" title="三次握手"></a>三次握手</h4><p><img src="./read-http-the-definitive-guide/tcp-three-way-handshake.png" alt="TCP三次握手" style="zoom:50%;"></p>
<p>步骤：</p>
<ul>
<li>请求新的TCP连接时，客户端向服务器发送一个小的TCP分组（通常是40~60个字节）。这个分组中设置一个特殊的SYN标记，说明是一个连接请求。</li>
<li>如果服务器接受了连接，就会对一些连接参数进行计算，并向客户端回送一个TCP分组，这个分组中的SYN和ACK标记都被置位，说明连接请求已被接受。</li>
<li>最后客户端向服务器回送一条确认消息，通知它连接已成功建立，现代的TCP栈都允许客户端在这个确认分组中发送数据。</li>
</ul>
<p>HTTP事务通常不会交换太多数据，所以SYN/SYN+ACK握手会产生一个可测量的时延，TCP连接的ACK分组通常足够大可以承载整个HTTP请求报文，很多HTTP服务器响应报文（响应包含装饰性图片的小型HTML文件或对浏览器高速缓存请求产生的304Not Modified响应）都可以放入一个IP分组中去。</p>
<h4 id="延迟确认"><a href="#延迟确认" class="headerlink" title="延迟确认"></a>延迟确认</h4><p>TCP自己的确认机制确保数据的成功传输（因特网自身无法确保可靠的分组传输，路由器超负荷可以随意丢弃分组）</p>
<p>每个TCP段都有一个序列号和数据完整性校验和，每个段的接收者收到完好的段时，都会向发送者会送小的确认分组，如果发送者没有在指定的窗口时间内收到确认信息就认为分组已被破坏或损毁并重发数据。确认报文很小所以TCP允许在发往相同方向的输出分组中对其进行捎带，即将返回的确认信息和输出的数据分组结合在一起。“延迟确认”就是为了增加确认报文找到同向传输数据分组的可能性。“延迟确认”算法会在一个特定的窗口时间（通常是100~200毫秒）内将输出确认存放在缓冲区中，以寻找能够捎带它的输出数据分组，如果再那个时间段内没有输出数据分组就将确认信息放在单独的分组中传送。但HTTP具有双峰特征的请求-应答行为降低了捎带信息的可能，即没有足够的相反方向回传分组，会映入相当大的时延。</p>
<h4 id="TCP慢启动"><a href="#TCP慢启动" class="headerlink" title="TCP慢启动"></a>TCP慢启动</h4><p> TCP慢启动就是TCP连接会随着时间进行自我“调谐”，起初会限制连接的最大速度，如果数据成功传输会随着时间的推移提高传输的速度，用于防止因特网的突然过载和拥塞。</p>
<p>TCP慢启动实现的机制就是限制一个TCP端点在任意时刻可以传输的分组数。每成功接收一个分组发送端就有了发送另外两个分组的权限，以此类推，称为“打开拥塞窗口”。即TCP数据传输的性能取决于TCP连接的使用期。已调谐连接的速度要比新连接的速度快一些，HTTP中可以重用现存连接即“持久连接”。</p>
<h4 id="Nagle算法"><a href="#Nagle算法" class="headerlink" title="Nagle算法"></a>Nagle算法</h4><p>应用程序可以通过TCP的数据流接口将任意尺寸的数据（一次一次字节也可以）放入TCP栈中，但由于每个TCP段都至少装载了40个字节的标记和首部，如果发送大量包含少量数据的分组就会造成网络性能下降（发送端傻窗口综合症）。Nagle算法在试图发送一个分组之前将大量TCP数据绑定在一起，鼓励发送全尺寸的段，只有在所有其他的分组都被确认之后才允许发送非全尺寸的分组。如果其他分组仍然在传输过程中就将那部分数据缓存起来，只有当挂起分组被确认或者缓存中积累了足够发送一个全尺寸分组的数据时才会将缓存的数据发送出去。Nagle算法情况下小的HTTP报文可能无法填满一个分组可能会因为等待永远不会到来的额外数据而产生时延，同时会在确认分组到达之前阻止数据的发送（确认分组会被延迟确认算法延迟）。</p>
<h4 id="TIME-WAIT累计和端口耗尽"><a href="#TIME-WAIT累计和端口耗尽" class="headerlink" title="TIME_WAIT累计和端口耗尽"></a>TIME_WAIT累计和端口耗尽</h4><p>当某个TCP端点关闭TCP连接时，会在内存中维护一个小的控制块，用来记录最近所关闭连接的IP地址和端口号，这类信息会维持所估计的最大分段使用期的两倍（2MSL），确保在这段时间内不会创建具有相同地址和端口号的新连接。高速路由器的使用使得重复分组几乎不可能在连接关闭后的几分钟之后出现在服务器上，如果将2MSL设置过小就会造成分组被复制，如果来自之前连接的复制分组插入了具有相同连接值的新TCP流会破坏TCP数据。</p>
<p>MSL（Maximum Segment Lifetime）即报文最大生存时间（报文在网络上存在的最长时间，超过这个时间报文将被丢弃）。IP数据报中的TTL域（time to live）即长存时间是由源主机设置初始值，表示的是IP数据报可以经过的最大路由数，每经过一个处理它的路由器此值减1，当此值为0是数据报将会丢弃。2MSL即两倍的MSL，当TCP一端发起主动关闭，在发出最后一个ACK包后即第3次握手完成后发送了第四个握手的ACK包就进入TIME_WAIT状态，必须在此状态上停留2MSL时间，等待2MSL时间的目的是怕最后一个ACK包对方没收到，那么对方在超时后将重发第三次握手的FIN包，主动关闭端接到重发的FIN包后可以再发一个ACK应答包，如果没有进入TIME_WAIT而是直接转移到CLOSE状态可能会有另一对应用进程打开同一个连接（即使用同一对端口号），这个时候FIN包会使后来的连接实例终止。</p>
<p>2MSL通常不是什么问题，在性能基准环境下（通常只有一台或几台用来产生流量的计算机连接到系统中）限制了连接到服务器的客户端的IP地址数并且服务器通常在HTTP的默认TCP端口80上进行监听，这样用TIME_WAIT防止端口号重用情况下只有端口号可以随意改变，但可用源端口有限可能会遇到TIME_WAIT端口耗尽问题。</p>
<h3 id="HTTP连接"><a href="#HTTP连接" class="headerlink" title="HTTP连接"></a>HTTP连接</h3><h4 id="Connection首部"><a href="#Connection首部" class="headerlink" title="Connection首部"></a>Connection首部</h4><p>HTTP允许在客户端和源端服务器之间存在一串HTTP中间实体（代理、高速缓存等），两个相邻的HTTP应用程序会为它们共享的连接应用一组选项。Connection首部字段中有一个由逗号分隔的连接标签列表，这些标签为此连接指定了一些不会传播到其他连接中去的选项（报文在转发给下一跳地址之前会将Connection首部以及Connection中列出的所有首部删除，可能会有少量没有作为Connection首部值列出，但一定不能被代理转发的逐跳首部，如Prxoy-Authenticate、Proxy-Connection、Transfer-Encoding和Upgrade），Connection首部可以防止无意中对本地首部的转发，将逐跳首部名放入Connection首部称为“对首部的保护”。Connection首部可以承载3中不同类型的标签：HTTP首部字段名，列出只与此连接有关的首部；任意标签值，用于描述此连接的非标准选项；值close说明操作完成之后需关闭这条持久连接。</p>
<h4 id="串行事务处理"><a href="#串行事务处理" class="headerlink" title="串行事务处理"></a>串行事务处理</h4><p>如果每个事务都需要一条新的连接（串行地建立）连接时延和慢启动就会叠加起来，提高HTTP的连接性能：并行连接、持久连接、管道化连接、复用的连接（交替传送请求和响应报文）。</p>
<ul>
<li><p>并行连接</p>
<p>HTTP允许客户端打开多条连接，并行地执行多个HTTP事务，每个事务都有自己的连接，连接的时延是重叠的，在单条连接没有充分利用带宽的情况下可以提高加载速度，如果带宽优先可能不会提升速度，并且打开大量连接会消耗很多内存资源可能引发自身性能问题，并行连接给人的主观感觉“更快一些”。</p>
</li>
<li><p>持久连接</p>
<p>HTTP/1.1（以及HTTP/1.0的各种增强版本）允许HTTP设备在事务处理结束之后将TCP连接保持在打开状态以便为未来的HTTP请求重用现存的连接，在事务处理结束之后仍然保持在打开状态的TCP连接即为持久连接，会在不同事务之间保持打开状态，直到客户端或服务器决定将其关闭为止。重用持久连接，可以避开缓慢的连接建立阶段同时可以避免慢启动的拥塞适应阶段。持久连接有两种类型：HTTP/1.0+“keep-alive”连接和HTTP/1.1“persistent”连接。</p>
<p>实现HTTP/1.0 keep-alive连接的客户端可以通过包含Connection：Keep-Alive首部请求将一条连接保持在打开状态，如果服务器愿意为下一条请求将连接保持在打开状态，就在响应中包含相同的首部，如果响应中没有Connection：Keep-Alive首部客户端就认为服务器不支持keep-alive并且会在发回响应报文之后关闭连接。Keep-Alive通用首部可以通过指定的、逗号分隔的选项调节Keep-Alive行为，timeout由Keep-Alive响应首部发送，估计了服务器希望将连接保持在活跃状态的时间，max有Keep-Alive响应首部发送，估计服务器还希望为多少个事务保持此连接的活跃状态（timeout和max都不是承诺值）。Keep-Alive首部完全可选但只有在提供Connection：Keep-Alive时才能使用。只有在无需检测到连接的关闭即可确认报文实体主体部分长度的情况下（即实体的主体部分必须有正确的Content-Length，有多部件媒体类型或用分块传输编码的方式进行了编码）才能将连接保持在打开状态。在keep-alive信道回送了错误的Content-Length会使事务处理的另一端无法精确地检测出一条报文的结束和另一条报文的开始。如果客户端在收到完整的响应之前连接关闭都应该重试请求（除非重复发送请求会产生其他一些副作用）。哑代理问题由盲中继（只是将字节从一个连接转发到另一个连接中去，不对Connection首部进行特殊的处理）所引起，在服务器和客户端都认为对方认可keep-alive信道但哑代理并不认可的情况下，客户端再次发送请求时哑代理会忽略起请求（一直等待源端服务器关闭连接）直到客户端或服务器将连接超时后关闭为止。网景的变通做法是浏览器向代理发送非标准的Proxy-Connection扩展首部而不是官方支持的Connection首部，盲中继会将Proxy-Connection首部转发给服务器但服务器会忽略此首部（不会带来问题），如果是聪明的代理（可以理解持久连接的握手操作）就用Connection首部取代Proxy-Connection首部创建持久连接。但是这种做法在面对多层次代理（例如哑代理任意一侧有聪明代理）还是会出现问题。</p>
<p>HTTP/1.1持久连接在默认情况下是激活的，要在事务处理结束之后将连接关闭HTTP/1.1应用程序必须向报文中显式地添加一个Connection：close首部，否则HTTP/1.1连接就维持在打开状态（客户端和服务器仍然可以随时关闭空闲连接，故不发送Connection：close并不意味这服务器承诺永远将连接保持在打开状态）。只有当连接上所有的报文都有正确的、自定义报文长度时（即实体主体部分的长度和相应的Content-Length一致或者是用分块传输编码方式编码）连接才能保持持久。HTTP/1.1的代理必须能够分别管理与客户端和服务器的持久连接（每个持久连接都只适用于一跳传输）。HTTP设备可以在任意时刻关闭连接（不管Connection首部取何值），如果客户端在收到整条响应之前连接关闭都应该重新发起请求（除非重复发起请求会产生副作用）。一个用户客户端对任何服务器或代理最多只能维护两条持久连接以防服务器过载。</p>
</li>
<li><p>管道化连接</p>
<p>在持久连接上使用请求管道，在响应到达之前可以将多条请求放入队列，当第一条请求通过网络流向服务器时第二条和第三条请求也可以开始发送。必须按照与请求相同的顺序回送HTTP响应（HTTP报文没有序列号标签，失序后无法将其与请求匹配起来）。客户端需要能够对过早关闭的连接重新发出请求。客户端不应该使用管道化的方式发送会产生副作用的请求（比如POST），出错之后管道化的方式会阻碍客户端了解服务器执行的是一系列管道化请求中的哪一些，并且无法安全地重试POST这样的非幂等请求（事务幂等性即一个事务不管执行一次还是很多次得到的结果都相同。），可能会存在某些方法永远不会被执行。</p>
</li>
</ul>
<h3 id="关闭连接"><a href="#关闭连接" class="headerlink" title="关闭连接"></a>关闭连接</h3><p>所有HTTP客户端、服务器或代理都可以在任意时刻关闭一条TCP传输连接，通常会在一条报文结束时关闭连接，出错的时候任意时刻关闭连接。在持久连接空闲一段时间服务器可能会将其关闭但服务器无法确认在它关闭“空闲”连接时客户端是否有数据发送。</p>
<p>TCP连接是双向的，每一端都有一个输入队列和一个输出队列，用于数据的读和写。放入一端输出队列中的数据最终会出现在另一端的输入。应用程序可以关闭TCP输入和输出信道中的任意一个（半关闭）或者两者都关闭（完全关闭）。关闭输出信道总是安全的（连接另一端从缓冲区读出所有数据之后收到流结束的通知可以得知连接关闭），关闭输入信道会给传送数据的机器回送一条“连接被对端重置”的报文，操作以系统会将这种情况当做错误处理，并删除对端还未读取的所有缓存数据，对于管道化连接可能会使已经接受的响应数据（暂存在操作系统的缓冲区但应用程序还未读取）丢失。</p>
<p>正常关闭连接应该先关闭输出信道，然后周期性的检查其输入信道的状态（查找数据或流的末尾），如果一定时间区间内对端没有关闭输入信道，应用程序可以强制关闭连接（节省资源）。</p>
<h2 id="第5章-Web服务器"><a href="#第5章-Web服务器" class="headerlink" title="第5章 Web服务器"></a>第5章 Web服务器</h2><p>所有web服务器都要能够接收请求资源的HTTP请求然后将内容回送给客户端。Web服务器逻辑实现了HTTP协议、管理web资源并负责提供web服务器的管理功能。</p>
<p><img src="./read-http-the-definitive-guide/web-server-request-steps.png" alt="基本web服务器请求步骤" style="zoom:50%;"></p>
<h3 id="客户端用户确认"><a href="#客户端用户确认" class="headerlink" title="客户端用户确认"></a>客户端用户确认</h3><ul>
<li>对web服务器进行反向DNS配置</li>
<li>通过ident协议找到发起HTTP连接的用户名（服务器在客户端打开HTTP连接后打开到客户端ident服务器端口的连接发起请求询问与新连接相对应的用户名）</li>
</ul>
<h3 id="服务器结构"><a href="#服务器结构" class="headerlink" title="服务器结构"></a>服务器结构</h3><ul>
<li>单线程web服务器：一次只处理一个请求，直到完成为止。严重的性能问题</li>
<li>多线程及多线程web服务器：多个进程或者线程同时对请求进行处理。消耗太多的内存或系统资源</li>
<li>复用I/O的服务器：同时监视所有连接上的活动，当连接状态发生变化就对那条连接进行少量的处理，处理结束后将连接返回到开放连接列表中等待下一次状态变化。</li>
<li>复用的多线程web服务器：多线程与复用功能结合，多个线程中的每一个都在观察打开的连接（或打开的连接中的一个子集）并对每条连接执行少量的任务。</li>
</ul>
<h3 id="服务器中资源的映射"><a href="#服务器中资源的映射" class="headerlink" title="服务器中资源的映射"></a>服务器中资源的映射</h3><ul>
<li>docroot：document root（文档根目录），服务器文件系统中一个专门用于存放web内容的文件夹。web服务器从请求报文中获取URI，将其附加在文档根目录的后面。但不能让相对URL退到docroot之外</li>
<li>目录列表：接收对目录URL的请求，返回一个默认的“索引文件”或者返回一个包含目录内容的HTML页面，也可以返回一个错误</li>
<li>动态内容资源的映射：映射到按需动态生成内容的程序上</li>
<li>服务端包含项：SSI，某个资源被标识为存在服务器端包含项，服务器就会将其发送给客户端之前对资源内容进行处理，可以用变量的值或可执行脚本的输出来取代特定的模板（通常包含在特定HTML注释中）</li>
<li>访问控制：访问受控资源的请求到达，服务器可以根据客户端的IP地址或者要求输入密码进行访问控制</li>
</ul>
<h3 id="响应报文中MIME类型确认"><a href="#响应报文中MIME类型确认" class="headerlink" title="响应报文中MIME类型确认"></a>响应报文中MIME类型确认</h3><ul>
<li>MIME类型（mime.types）：web服务器会为每个资源扫描一个包含了所有扩展名的MIME类型的文件以确定其MIME类型</li>
<li>魔法分类（Magic typing）：Apache web服务器可以扫描每个资源的内容并将其与一个已知模式表（魔法文件）匹配以决定每个文件的MIME类型</li>
<li>显式分类（Explicit typing）：不考虑文件的扩展名或内容，强制特定文件或目录内容拥有某个MIME类型</li>
<li>类型协商：通过与用户的协商来决定使用哪种格式（以及相关的MIME类型）最好（服务器可以用多种文档格式来存储资源）</li>
</ul>
<h2 id="第6章-代理"><a href="#第6章-代理" class="headerlink" title="第6章 代理"></a>第6章 代理</h2><h3 id="代理与网关的对比"><a href="#代理与网关的对比" class="headerlink" title="代理与网关的对比"></a>代理与网关的对比</h3><p>严格来说，代理连接的是两个或多个使用相同协议的应用程序，而网关连接的则是两个或多个使用不同协议的端点（协议转换器）。但实际上代理和网关的区别模糊，代理也经常要做一些协议转换工作。</p>
<h3 id="代理功能"><a href="#代理功能" class="headerlink" title="代理功能"></a>代理功能</h3><p>可以接触到所有流过的HTTP流量，并对其进行监视或修改。</p>
<h3 id="代理使用方法示例"><a href="#代理使用方法示例" class="headerlink" title="代理使用方法示例"></a>代理使用方法示例</h3><ul>
<li>儿童过滤器： 过滤器代理阻止访问某些内容</li>
<li>文档访问控制：实现访问控制策略，创建审核跟踪机制，适用于大型企业环境或其他分布式机构。集中式代理服务器可以对所有访问控制功能进行配置。</li>
<li>安全防火墙：代理服务器会在网络中的单一安全阶段限制那些应用层协议数据可以流入或流出一个组织，还可以提供用来消除病毒的web和E-mail代理使用的那种挂钩程序。</li>
<li>web缓存：代理缓存维护了常用文档的本地副本，并将它们按需提供。</li>
<li>反向代理：假扮web服务器，接受发给web服务器的真实请求，发起与其他服务器的通信定位所请求内容，又称为替代物。可以用来提高访问慢速web服务器上公共内容的性能（服务器加速器），还可以将替代物与内容路由功能配合以创建按需复制内容的分布式网络。</li>
<li>内容路由器：代理服务器根据因特网流量状况以及内容类型将请求导向特定的web服务器，也可以用来实现各种服务级的请求（更高的性能或者过滤服务）。</li>
<li>转码器：代理服务器在将内容发送给客户端之前可以修改内容的主体格式。</li>
<li>匿名者：匿名者代理会主动从HTTP报文中删除身份特性（如客户端IP地址、From首部、Referer首部、cookie、URI的会话ID），提供高度的私密性和匿名性。</li>
</ul>
<h3 id="代理部署位置"><a href="#代理部署位置" class="headerlink" title="代理部署位置"></a>代理部署位置</h3><ul>
<li><p>出口代理</p>
<p>代理固定在本地网络的出口点，可以针对外部黑客提供防火墙保护、降低带宽费用、过滤不恰当内容。</p>
</li>
<li><p>访问（入口）代理</p>
<p>代理常备放在ISP访问点上用来处理来自用户的聚合请求，可以作为缓存代理提高下载速度。</p>
</li>
<li><p>反向代理</p>
<p>代理通常会被部署在网络的边缘，在web服务器之前，可以处理所有传送给web服务器的请求并只在必要时向web服务器请求资源。反向代理通常会直接冒用web服务器的名字和IP地址（所有的请求就会被发送给代理而不是服务器）。</p>
</li>
<li><p>网络交换代理</p>
<p>将具有足够处理能力的代理放在网络之间的因特网对等交换点上，通过缓存来减轻因特网节点的拥塞并对流量进行监视。</p>
</li>
</ul>
<h3 id="代理层次结构的内容路由"><a href="#代理层次结构的内容路由" class="headerlink" title="代理层次结构的内容路由"></a>代理层次结构的内容路由</h3><p>代理层次结构不一定是静态的（按照父子代理的既定顺序传递），代理可以将报文转发给一个不断变化的代理服务器和原始服务器集。</p>
<p>动态选择父代理实例：</p>
<ul>
<li><p>负载均衡</p>
<p>子代理可以根据当前父代理上的工作负载级别来决定如何选择一个父代理</p>
</li>
<li><p>地理位置附近的路由</p>
<p>子代理可能会选择负责原始服务器所在物理区域的父代理</p>
</li>
<li><p>协议/类型路由</p>
<p>子代理可能会根据URI将报文转发到不同的父代理和原始服务器上去。某些特定类型的URI可能要通过一些特殊的代理服务器转发请求。</p>
</li>
<li><p>基于订购的路由</p>
<p>为高性能服务付费的发布者的URI会被转发到大型缓存或压缩引擎上</p>
</li>
</ul>
<h3 id="代理获取流量"><a href="#代理获取流量" class="headerlink" title="代理获取流量"></a>代理获取流量</h3><p>客户端通常会直接与web服务器进行通信，有四种常见方式可以使客户端流量流向代理</p>
<ul>
<li><p>修改客户端</p>
<p>很多客户端都支持收工和自动的代理配置，将其配置为使用代理服务器后客户端就会将HTTP请求直接发送给代理。</p>
</li>
<li><p>修改网络</p>
<p>依赖于监视HTTP流量的交换设备及路由设备，在客户端不知情的情况下对流量进行拦截并导入代理。</p>
</li>
<li><p>修改DNS的命名空间</p>
<p>反向代理假扮web服务器的名字和IP地址实现是通过手工编辑DNS名称列表或者用特殊的动态DNS服务器根据需要来确定适当的代理或服务器。有时真实服务器的IP地址和名称被修改，反向代理使用之前的地址和名称。</p>
</li>
<li><p>修改web服务器</p>
<p>将某些web服务器配置为向客户端发送一条HTTP重定向命令（响应码305）将客户端重定向到一个代理上去。</p>
</li>
</ul>
<h3 id="客户端的代理设置"><a href="#客户端的代理设置" class="headerlink" title="客户端的代理设置"></a>客户端的代理设置</h3><ul>
<li><p>手工配置：显式地设置要使用的代理</p>
</li>
<li><p>预先配置浏览器：浏览器厂商或发行商对浏览器的代理设置进行手工配置后发给客户</p>
</li>
<li><p>代理的自动配置（PAC）</p>
<p>客户端通过一个指向用JavaScript编写的代理自动配置文件的URI取出JavaScript文件（PAC文件）运行，决定是否使用代理和使用哪个代理。</p>
<p>手工代理配置简单但死板并只能为所有内容指定唯一的一个代理服务器，而且不支持故障转移。浏览器获取PAC文件后可以用JavaScript逻辑为每次访问计算恰当的代理服务器，每个PAC文件都必须定义一个<code>FindProxyForURL(url,host)</code>函数，用来计算访问URI时使用适当的代理服务器。</p>
</li>
<li><p>wpad代理发现：web代理自动发现协议会自动检测出浏览器可以从哪个“配置服务器”下载到一个自动配置文件，即自动查找合适的PAC文件（自动手工提供URI）。</p>
</li>
</ul>
<h3 id="代理URI与服务器URI不同"><a href="#代理URI与服务器URI不同" class="headerlink" title="代理URI与服务器URI不同"></a>代理URI与服务器URI不同</h3><p>客户端向web服务器发送请求时，请求行中只包含部分URI（没有方案、主机和端口）；客户端向代理发送请求时，请求行中需要包含完整的URI。客户端直接与单个服务器对话因为单个服务器都知道自己的主机名和端口，不存在虚拟主机，无需发送方案和主机。代理需要知道目标服务器的名称才能建立与服务器的连接，基于代理的网关要知道URI的方案才能连接到FTP资源和其他方案上去。但有些代理可能对客户端是不可见的（即没有将客户端配置为使用代理客户端的流量也可能会经过替代物或拦截代理），这种情况下客户端认为在与web服务器对话，不会发送完整的URI。</p>
<p>故通用的代理服务器应该支持请求报文中的完整URI同时也应该支持部分URI。</p>
<ul>
<li>如果提供完整URI直接使用；</li>
<li>如果提供部分URI和Host首部就利用Host首部确定原始服务器的名字和端口号；</li>
<li>如果仅仅提供部分URI需要区分代理情况<ul>
<li>替代物可以用真实服务器的地址和端口号来配置代理</li>
<li>流量被拦截的情况下如果拦截者可以提供原始的IP地址和端口，代理可以用拦截技术提供的IP地址和端口号</li>
<li>所有方法失败了即代理没有足够的信息确定原始服务器就必须返回一条错误报文</li>
</ul>
</li>
</ul>
<p>虚拟主机web服务器会在很多web站点间共享同一个物理web服务器，故部分URI的请求到达需要知道目的web站点的主机名（虚拟托管的docroot），虚拟主机web服务器采用的做法是使用Host首部来承载主机和端口信息。</p>
<h3 id="URI解析"><a href="#URI解析" class="headerlink" title="URI解析"></a>URI解析</h3><ul>
<li><p>没有代理时URI的解析</p>
<p><img src="./read-http-the-definitive-guide/no-proxy-uri-resolution.png" alt="没有代理URI的解析" style="zoom:50%;"></p>
</li>
<li><p>有显式代理时URI的解析</p>
<p><img src="./read-http-the-definitive-guide/parsing-with-explicit-proxy-uri.png" alt="有显式代理时URI的解析" style="zoom:50%;"></p>
<p>用户在浏览器的地址窗口中输入<code>oreilly</code>时，发送给代理的就是<code>http://oreilly/</code>。</p>
</li>
<li><p>有拦截代理时URI的解析</p>
<p><img src="./read-http-the-definitive-guide/has-interception-proxy-uri-resolution.png" alt="有拦截代理URI的解析" style="zoom:50%;"></p>
<p>有拦截代理的情况下，客户端DNS解析的过程同没有代理相同，在第（4a）步中客户端成功解析了主机名并有一张IP地址列表（有些IP地址可能已经停用），通常客户端会尝试连接每个IP地址直到成功，但拦截代理会将第一次连接请求拦截成功不会连接到原始服务器上（可能已停用），客户端认为它在与web服务器进行成功对话，但当代理准备与真正的原始服务器交互时才会发现那个IP地址指向的可能是一个已停用的服务器，这时为了提供与浏览器相同级别的容错机制代理需要解析Host首部的主机名或者通过对IP地址的反向DNS查找来尝试其他IP地址。</p>
</li>
</ul>
<h3 id="追踪报文"><a href="#追踪报文" class="headerlink" title="追踪报文"></a>追踪报文</h3><p>Via首部字段列出了与报文途径的每个中间节点（代理或网关）有关的信息，报文每经过一个节点都必须将这个中间节点添加到Via列表的末尾。包含一个由逗号分隔的路标，每个路标都表示一个独立的代理服务器或网关，且包含与那个中间节点的协议和地址有关的信息。有些代理会为使用非HTTP协议的服务器提供网关的功能，Via首部可以记录这些协议转换。当代理服务器作为网络防火墙的一部分使用时不应该转发防火墙后面那些主机的名字和端口号，可以使用适当的假名来取代主机的名字，需要隐藏内部网络设计和拓扑结构的组织代理服务器应该将一个有序Via路标条目序列合并成一个联合条目。</p>
<p>用户可以通过TRACE方法跟踪经代理链传输的请求报文，观察报文经过了那些代理以及每个代理如何对请求报文进行修改。TRACE请求到达目的服务器整条请求报文都会被封装在一条HTTP响应的主体中回送客户端。可以通过Max-Forwards（最大转发次数）首部来测试代理链是否在无限循环中转发报文或查看链中特定代理服务器的效果。</p>
<h3 id="代理认证"><a href="#代理认证" class="headerlink" title="代理认证"></a>代理认证</h3><p>代理服务器对于受限请求可以返回一个要求使用访问整数的407状态码，以及一个用于描述怎样提供这些证书的Proxy-Authenticate首部字段，客户端通过搜集来的有效证书在次发起请求后代理才会将原始请求沿着传输链路向下传送。</p>
<h3 id="代理的互操作性"><a href="#代理的互操作性" class="headerlink" title="代理的互操作性"></a>代理的互操作性</h3><p>代理必须对不认识的首部字段进行转发而且必须维持同名首部字段的相对顺序，对于不熟悉的某个方法也应该尽可能尝试着将其转发到下一跳节点。</p>
<h2 id="第7章-缓存"><a href="#第7章-缓存" class="headerlink" title="第7章 缓存"></a>第7章 缓存</h2><p>web缓存是可以自动保存常见文档副本的HTTP设备，使用web缓存可以减少冗余的数据传输、缓解网络瓶颈的问题、降低对原始服务器的要求、降低距离时延。</p>
<ul>
<li>冗余的数据传输就是很多客户端访问一个原始服务器页面时服务器会多次地传输同一份文档，缓存可以保留第一条服务器响应的副本，后继请求可以使用缓存的副本来应对。</li>
<li>带宽瓶颈是由于本地网路客户端提供的带宽往往比远程服务器提供的带宽要宽，客户端会以路径上最慢的网速访问服务器，如果客户端从一个快速局域网的缓存中得到一份副本，可以提高性能（特别是比较大的文件）</li>
<li>瞬间拥塞是由于突发事件使很多人几乎同时访问一个web文档，由此造成的过多流量峰值可能会使网络和web服务器发生灾难性的崩溃。</li>
<li>距离时延：每台网络路由器都会增加因特网流量的时延，光速自身也会造成显著的时延。</li>
</ul>
<h3 id="缓存命中和未命中"><a href="#缓存命中和未命中" class="headerlink" title="缓存命中和未命中"></a>缓存命中和未命中</h3><p>缓存命中：可以用已有的副本为某些达到缓存的请求提供服务</p>
<p>缓存未命中：一些到达缓存的请求可能由于没有副本可用而被转发给原始服务器</p>
<p>HTTP没有为用户提供一种手段来区分缓存是否命中，无论响应是缓存命中的还是访问原始服务器得到这两种情况下响应码都是200 OK。客户端可以通过Date首部进行区分，如果响应中的日期与当前日期相比较早就可以认为这是一条缓存的响应，也可通过Age首部分辨出这条响应的使用期。</p>
<p>HTTP再验证：原始服务器的内容可能会发生变化，缓存要不时对其进行检测，看看保存的副本是否是服务器上最新的副本，理论上缓存可以在任意时刻，以任意的频率对副本进行再验证，但大部分缓存只有在客户端发起请求并且副本旧的需要检测的时候才会对副本进行再验证。HTTP中用来再验证最常用的是If-Modified-Since首部</p>
<ul>
<li>再验证命中（缓存命中）：缓存对缓存的副本进行再验证（向原始服务器发送一个小的再验证请求），服务端以一个小的304 Not Modified进行相响应（内容没有变化）</li>
<li>再验证未命中：服务器对象与已缓存副本不同，服务端向客户端发送一条普通的、带有完整内容的HTTP 200 OK响应。</li>
<li>对象被删除：服务器对象已经被删除，服务器回送一个404 Not Found响应，缓存也会将其副本删除</li>
</ul>
<p>命中率：缓存命中率、缓存命中比例、文档命中率，由缓存提供服务的请求所占比例。</p>
<p>字节命中率：缓存提供的字节在传输的所有字节中所占的比例（文档由于不是同一尺寸故文档命中率不能说明一切），文档命中率说明阻止了多少通往外部网络的web事务（事务有一个通常很大的固定时间延迟），提高文档命中率可以降低整体延迟。字节命中率说明了阻止了多少字节传向因特网，提高字节命中率可以节省带宽。</p>
<h3 id="缓存的拓扑结构"><a href="#缓存的拓扑结构" class="headerlink" title="缓存的拓扑结构"></a>缓存的拓扑结构</h3><p>用户：</p>
<ul>
<li>私有缓存（专用缓存）：个人的缓存，web浏览器中有内建的私有缓存</li>
<li>公有缓存：特殊的共享代理服务器（缓存代理服务器、代理缓存），从本地缓存中提供文档或者代表用户与服务器进行联系，可以接受来自多个用户的访问，可以通过它更好的减少冗余流量。</li>
</ul>
<p>层次结构：在较小缓存中未命中的请求会被导向较大的父缓存。</p>
<p>网状缓存中的代理缓存之间会以更加复杂的方式进行对话，做出动态的缓存通信决策，决定与哪个父缓存进行对话，或者直接连接原始服务器，也可称为内容路由器（这种代理缓存会决定选择何种路由对内容进行访问、管理和传送）。缓存之间这些更为复杂的关系允许不同的组织互为对等实体，提供可选的对等支持的缓存称为兄弟缓存。</p>
<h3 id="文档过期与服务器再验证"><a href="#文档过期与服务器再验证" class="headerlink" title="文档过期与服务器再验证"></a>文档过期与服务器再验证</h3><p>通过特殊的HTTP Cache-Control首部和Expires首部，HTTP让原始服务器向每个文档附加了一个“过期日期”，这些首部说明了在多长时间内可以将这些内容视为新鲜的，在缓存文档过期之前，缓存可以以任意频率使用这些副本而无需与服务器联系（除非客户端请求中包含有组织提供已缓存或未验证资源的首部）。一旦已缓存文档过期缓存就必须与服务器进行核对，询问文档是否被修改过，如果被修改就要获取一份新鲜的副本。Expires首部指定一个绝对的过期日期，Cache-Control：max-age首部值定义了文档的最大使用期（最大的合法生存时间，以秒为单位）。</p>
<p>文档过期并不意味着已缓存文档与原始服务器上活跃文档绝对有区别，只是表明需要核对即服务器再验证。如果再验证显示内容发生了变化，缓存获取新文档副本并将其存储在旧文档位置同时发送给客户端，如果再验证显示内容没有发生变化，缓存只需要获取新的首部，包括一个新的过期时间然后对已缓存文档的首部进行更新。条件GET即只有条件为真web服务器才会返回对象。</p>
<ul>
<li><p>If-Modified-Since:Date</p>
<p>如果从指定日期之后文档被修改过了就执行请求的方法</p>
<p>IMS请求（If-Modified-Since再验证请求），如果自指定日期后文档被修改了，通常GET方法就会成功执行，携带新首部（包含了新的过期日期）的新文档会被返回给缓存。如果自指定日期后文档没被修改过会向客户端返回一个304 Not Modified响应报文（包含了新的过期日期），不会返回文档主体。同时原始服务器可以将最后的修改日期附加到所提供的文档上去，当缓存要对已缓存文档进行再验证时，If-Modified-Since首部可以携带最后修改副本的日期，服务器可以比较缓存中的最后修改日期和服务器文档当前的最后修改日期。</p>
</li>
<li><p>If-None-Match:<tags>实体标签再验证</tags></p>
<p>服务器可以为文档提供特殊的标签，而不是将其与最近修改日期相匹配，如果已缓存标签与服务器文档中的标签有所不同，If-None-Match首部就会执行所请求的方法</p>
<p>实体标签（ETag）是附加到文档上的任意标签（引用字符串），可能包含了文档的序列号或版本号，或者文档内容的校验和及其他指纹信息。</p>
</li>
</ul>
<p>强弱验证器：不管相关的实体值以何种方式发生了变化，强实体标签都要发生变化；弱验证器允许对内容进行修改，但相关实体在语义上发生了比较重要的变化时弱实体标签也应该发生变化。</p>
<h3 id="缓存控制首部"><a href="#缓存控制首部" class="headerlink" title="缓存控制首部"></a>缓存控制首部</h3><ul>
<li>Cache-Control：no-store会禁止缓存对响应进行复制，缓存通常会像非缓存代理服务器一样，向客户端转发一条no-store响应然后删除对象。Pragma:no-cache首部是为了兼容HTTP/1.0+，HTTP/1.1应用程序都应该使用Cache-Control：no-cache。</li>
<li>Cache-Control：no-cache的响应实际上是可以存储在本地缓存区中，只是在与原始服务器进行新鲜度再验证之前缓存不能将其提供给客户端使用。</li>
<li>Cache-Control：max-age表示从服务器将文档传来之时起，可以认为此文档处于新鲜状态的秒数。</li>
<li>Expires首部指定过期日期，但由于很多服务器时钟都不同步（或不正确）最好还是用剩余秒数而不是用绝对时间来表示过期时间。</li>
<li>Cache-Control:must-revalidate，告诉缓存在事先没有跟原始服务器进行再验证的情况下不能提供这个对象的陈旧副本。缓存仍然可以随意提供新鲜的副本。如果缓存在进行must-revalidate新鲜度检查时原始服务器不可用，缓存就必须返回一条504 Gateway Timeout错误。</li>
</ul>
<p>试探性过期：响应中没有Cache-Control：max-age首部，也没有Expires首部，缓存可以依据任意算法计算出一个试探性最大使用期。上限保守为一天（通常站点设置为一周），没有任何新鲜周期线索的文档分配一个默认的新鲜周期（通常为一个小时或一天，保守一点设置为0）</p>
<p>web浏览器refresh（刷新）或reload（重载）按钮可以强制对浏览器或代理缓存中可能过期的内容进行刷新。refresh按钮会发布一个附加了Cache-Control请求首部的GET请求，这个请求会强制进行再验证或者无条件地从服务器获取文档。</p>
<h2 id="第8章-集成点：网关、隧道及中继"><a href="#第8章-集成点：网关、隧道及中继" class="headerlink" title="第8章 集成点：网关、隧道及中继"></a>第8章 集成点：网关、隧道及中继</h2><h3 id="网关"><a href="#网关" class="headerlink" title="网关"></a>网关</h3><p>网关可以作为某种翻译器使用，它抽象出了一种能够达到资源的方法。应用程序可以（通过HTTP或其他已定义接口）请求网关来处理某条请求，网关可以提供一条响应；网关也可以向数据库发送查询语句或者生成动态的内容，有些网关可以将HTTP流量转换为其他协议。</p>
<p>从对话在网关的哪一侧划分：</p>
<ul>
<li>服务器端网关：通过HTTP与客户端对话，通过其他协议与服务器通信（HTTP/*）</li>
<li>客户端网关：通过其他协议与客户端对话，通过HTTP与服务器通信（*/HTTP）</li>
</ul>
<p>将HTTP流量导向网关采用的方式和将流量导向代理相同，可以显示的配置浏览器使用网关（对流量进行透明的拦截）或者将网关配置为替代物（反向代理）。</p>
<h4 id="协议网关"><a href="#协议网关" class="headerlink" title="协议网关"></a>协议网关</h4><ul>
<li><p>服务器端web网关（HTTP/*）：请求流入原始服务器时，服务器端web网关会将客户端HTTP请求转换为其他协议</p>
</li>
<li><p>服务器端安全网关（HTTP/HTTPS）：通过网关对所有输入web请求加密已提供额外的隐私和安全性保护。客户端可以用普通的HTTP浏览web内容但网关会自动加密用户的对话。</p>
</li>
<li>客户端安全加速器网关（HTTPS/HTTP）：通常作为不可见的拦截网关或反向代理使用，接收安全的HTTPS流量，对安全流量进行解密，并向web服务器发送普通的HTTP请求，可以减轻原始服务器的负荷，但需确保网关和原始服务器之间的网络是安全的。</li>
</ul>
<h4 id="资源网关"><a href="#资源网关" class="headerlink" title="资源网关"></a>资源网关</h4><p>最常见的网关：应用程序服务器（服务端网关），会将目标服务器与网关结合在一个服务器中实现。用户通过HTTP连接到应用程序服务器后，应用程序服务器会将请求通过一个网关应用编程接口发给运行在服务器上的应用程序，之后会将其结果回送给客户端。</p>
<p>CGI：通用网关接口，标准接口集，web服务器可以用CGI来装载程序以响应特定URL的HTTP请求并收集程序的输出数据，将其放在HTTP响应中回送。CGI应用程序独立于服务器，可以用任意语言实现，对用户来时不可见，在服务器和众多的资源类型之间提供一种简单的、函数形式的粘合方式，用来处理各种需要的转换，可以防止一些糟糕的扩展对服务器可能造成破坏，但会造成性能的耗费。</p>
<p>服务器扩展API：可以使开发者改变服务器自身的行为或者尽可能提升能从服务器上获得的性能，</p>
<h3 id="隧道"><a href="#隧道" class="headerlink" title="隧道"></a>隧道</h3><p>可以通过HTTP应用程序访问使用非HTTP协议的应用程序</p>
<p>CONNECT建立HTTP隧道：CONNECT方法请求隧道网关创建一条到达任意目的服务器和端口的TCP连接（任意协议的任意服务器），并对客户端和服务器之间的后继数据进行盲转发，数据可以在任意时间流向任意方向。</p>
<p>CONNECT请求报文中除起始行之外与其他HTTP方法类似，起始行中方案为CONNECT，一个后面跟着冒号和端口号的主机取代了请求URI（主机和端口都必须指定）。CONNECT响应报文中和普通HTTP报文一样，响应码200表示成功，原因短语通常被设置为”Connection Established”，响应中不需要包含Content-Type首部。</p>
<p>SSL隧道：为了让SSL流量经现存的代理防火墙进行传输，可以将原始的加密数据放在HTTP报文中，通过普通的HTTP信道传送。（加密的SSL无法通过传统的代理服务器转发）</p>
<p>HTTPS协议（SSL上的HTTP）的网关操作：由网关（而不是客户端）初始化与远端HTTPS服务器的SSL会话，然后代表客户端执行HTTPS事务，响应由代理接受并解密，然后通过（不安全的）HTTP传送给客户端。</p>
<p>隧道认证：与代理的认证支持配合使用，要求使用的客户端进行使用权限认证</p>
<h3 id="中继"><a href="#中继" class="headerlink" title="中继"></a>中继</h3><p>没有完全遵守HTTP规范的简单HTTP代理，中继负责处理HTTP中建立连接的部分然后对字节进行盲转发。盲中继存在的一个常见问题及时无法正确处理Connection首部，可能会挂起keep-alive连接。</p>
<h2 id="第9章-web机器人"><a href="#第9章-web机器人" class="headerlink" title="第9章 web机器人"></a>第9章 web机器人</h2><h3 id="爬虫"><a href="#爬虫" class="headerlink" title="爬虫"></a>爬虫</h3><p>递归地追踪web链接的机器人会沿着HTML超链创建的网络爬行。</p>
<p>根集：爬虫开始访问的URL初始集合（一个好的根集：一些大的流行web站点、一个新创建页面的列表和一个不经常被链接的无名页面列表）</p>
<p>机器人必须知道它们到过何处避免环路的出现。</p>
<p>对访问过的地址进行管理：</p>
<ul>
<li><p>快速搜索：树和散列表、有损的存在位图</p>
<p>减小空间可以使用有损数据结构，比如存在位数组，用一个散列函数将每个URL都转换为一个定长的数字，这个数字在数组中有相关的“存在位”，爬行过一个URL后就将相应的存在位置位。（可能会有冲突）</p>
</li>
<li><p>检查点：将已访问的URL列表保存到硬盘，防止机器人程序崩溃</p>
</li>
</ul>
<p>文件系统连接环路：文件系统中可能存在某个目录可以指向’/‘的环路，’/‘目录下的文档可能会造成循环</p>
<p>动态虚拟web空间：利用网关应用程序构造出包含到同一服务器上虚构URL链接的HTML，请求虚构URL时服务器就会构建一个新的带有虚构URL的新HTML页面（例：日历程序中不停的请求下个月）</p>
<p>避免循环重复：</p>
<ul>
<li>通过将URL规范化为标准格式来消除URL别名重复的影响</li>
<li>广度优先的爬行：非深度优先</li>
<li>节流：限制一段时间内机器人可以从一个web站点获取的页面数量</li>
<li>限制URL的大小：拒绝爬行超出特定长度的URL（针对文件系统连接环路）</li>
<li>URL/站点黑名单：维护一个与机器人环路和陷阱相对应的已知站点和URL列表</li>
<li>模式检测：将具有重复组件的URL当做潜在的环路（针对文件系统连接环路，如’/subdir/subdir/subdir…’）</li>
<li>内容指纹：获取页面内容的字节并计算校验和</li>
<li>人工监视：诊断和日志</li>
</ul>
<h2 id="第11章-客户端识别与cookie机制"><a href="#第11章-客户端识别与cookie机制" class="headerlink" title="第11章 客户端识别与cookie机制"></a>第11章 客户端识别与cookie机制</h2><p>用户识别机制：</p>
<ul>
<li>承载用户身份信息的HTTP首部</li>
<li>客户端IP地址追踪，通过用户的IP地址对其进行识别</li>
<li>用户登录，用认证的方式来识别用户</li>
<li>胖URL，一种在URL中嵌入识别信息的技术</li>
<li>cookie，一种功能强大且高效的持久身份识别技术</li>
</ul>
<h3 id="HTTP首部"><a href="#HTTP首部" class="headerlink" title="HTTP首部"></a>HTTP首部</h3><ul>
<li>From首部包含用户的E-mail地址，考虑到隐私问题很少有浏览器会发送from首部，实际上from首部是由自动化的机器人或蜘蛛发送的</li>
<li>User-Agent首部可以将用户所用浏览器的相关信息告知服务器，包括程序的名称和版本，通常还包含操作系统的相关信息，但并没有为识别特定的用户提供太多有意义的帮助。</li>
<li>Refer而首部提供用户来源页面的URL，可以通过它理解用户的浏览行为。</li>
</ul>
<h3 id="客户端IP地址"><a href="#客户端IP地址" class="headerlink" title="客户端IP地址"></a>客户端IP地址</h3><p>web服务器可以找到承载HTTP请求的TCP连接另一端的IP地址。</p>
<p>缺点：客户端IP地址描述的是所用机器而不是用户、NAT的存在（将实际的客户端IP地址转换为一个共享的防火墙IP地址和不同的端口号）、很多因特网服务提供商都会在用户登录时为其动态分配IP地址、代理的存在</p>
<h3 id="用户登录"><a href="#用户登录" class="headerlink" title="用户登录"></a>用户登录</h3><p>浏览器对于为登录的用户请求会返回401状态码并添加WWW-Authentication首部要求用户登录，用户输入用户名和密码后请求中添加Authorization首部说明用户名和密码（已加密），浏览器会自动将其存储下来后再之后的每次请求中都想服务器发送Authorization首部在整个会话期间维持用户的身份。</p>
<h3 id="胖URL"><a href="#胖URL" class="headerlink" title="胖URL"></a>胖URL</h3><p>胖URL即包含了用户状态信息的URL。一般是在URL路径开始或结束的地方添加一些状态信息。</p>
<p>缺点：发送给其他人可能会无意中造成个人信息的泄露、服务器需要重写HTML页面、不再有公共访问的URL需要缓存、会话非持久（用户退出登录可能会丢失信息）、会话切换可能会丢失进展。</p>
<h3 id="cookie"><a href="#cookie" class="headerlink" title="cookie"></a>cookie</h3><p>cookie可以分为会话cookie和持久cookie，两者唯一的区别在于它们的过期时间。会话cookie在用户退出浏览器时会被删除，持久cookie的生存时间更长一些。cookie中包含了一个由名字=值的信息构成的任意列表，服务器通过Set-Cookie首部将其添加给用户。</p>
<p>cookie的基本思想就是让浏览器积累一组服务器特有的信息，每次访问服务器时都将这些信息提供给它，浏览器指向服务器发送服务器产生的那些cookie。cookie的domain属性控制哪些站点可以看到那个cookie。Path属性列出的URL路径前缀下所有cookie都是有效的。</p>
<p>cookie版本0中Set-Cookie首部有一个强制性的cookie名和cookie值，后面跟着可选的cookie属性：</p>
<ul>
<li>Expires，定义cookie的实际生存期，一旦到了过期日期就不会存储或发布这个cookie。日期格式为<code>Weekday, DD-Mon-YY HH:MM:SS GMT</code>，唯一合法时区为GMT，如果没有指定Expires，cookie就会在用户会话结束时过期。</li>
<li>Domain，没有指定域默认为产生Set-Cookie响应的服务器的主机名。域至少要有两个或者三个句号（防止出现.com，.edu等形式的域。</li>
<li>Path，没有指定路径的情况下设置为产生Set-Cookie响应的URL路径。</li>
<li>Secure，如果包含就只有在HTTP中使用SSL安全连接时才会发送cookie。</li>
</ul>
<p>cookie版本1中Set-Cookie2首部也有一个强制的cookie名和cookie值，和cookie0中有着同样的Domain、Path、Secure属性，没有Expires属性，新增属性：</p>
<ul>
<li>Version，强制，对应cookie规范的版本</li>
<li>Comment，可选，说明服务器准备如何使用这个cookie，用户可以通过检查此策略来确定是否允许使用带有这个cookie的会话</li>
<li>CommentURL，可选，提供一个URL指针，指向详细描述cookie目的及策略的文档</li>
<li>Discard，可选，提供了这个属性就会在客户端程序终止时指示客户端放弃这个cookie</li>
<li>Port，可选，有端口列表的情况下就只能向与列表中的端口相匹配的服务器提供cookie，如果单独提供关键字Port而没有值就只能向单签响应服务器的端口号提供cookie。</li>
</ul>
<p>使用cookie在请求事务中Web服务器会通过一系列的重定向、URL重写以及cookie设置来附加标识信息。</p>
<h2 id="第12章-基本认证机制"><a href="#第12章-基本认证机制" class="headerlink" title="第12章 基本认证机制"></a>第12章 基本认证机制</h2><p>HTTP的质询/响应机制（基本认证）：</p>
<p>用户第一次发起没有认证信息的请求，服务器用401状态码拒绝，并用WWW-Authenticate首部说明如何以及在哪里进行认证。客户端授权处理后重新发起请求，并在Authorization首部附上加密的密码和其他一些认证参数。成功后服务器返回200，可能会在Authentication-Info首部附加额外信息。</p>
<p>HTTP实现不同的资源使用不同的访问权限：服务器将受保护的文档组织成一个安全域，每个安全域都可以有不同的授权用户集。WWW-Authenticate响应首部指定要访问的安全域。</p>
<p>基本认证可能会泄露用户名和密码，由于编码方式简单或者将加密后的用户信息发送给服务器从而获得访问权，没有提供针对代理和中间人的中间节点的防护措施。</p>
<h2 id="第13章-摘要认证"><a href="#第13章-摘要认证" class="headerlink" title="第13章 摘要认证"></a>第13章 摘要认证</h2><p>永远不会以明文方式在网络上发送密码、有选择地防止对报文内容的篡改</p>
<p>发送密码的摘要。对可能的密码摘要的截获，服务器先想客户端发送一个特殊令牌（随机数），客户端在计算摘要之前先将这个随机数令牌附加到密码上去。</p>
<p>摘要认证如果按照目前的形式在每条请求都要又一次请求/质询的循环，这在基本认证中并不常见（浏览器通常会维护一些客户端数据来存储用户名和密码，认证后的每次请求通常都发送），但摘要认证中采用随机数来破坏重放攻击，这样客户端在收到质询之前就不一定总能判定应该发送怎样的Authorization首部。在摘要认证中采用了预授权，无需等待新的WWW-Authenticate质询就可以获得正确的随机数。常见的预授权有预先在质询后的响应中Authntication-Info首部中发送下一个随机数、允许在一小段时间内使用同一个随机数、客户端与服务器使用同步的、可预测的随机数生成算法。</p>
<p>保护空间：域值和被访问服务器的标准根URL结合在一起。通过域可以将服务器上的受保护资源划分为一组保护空间，每个空间都有自己的认证机制和授权数据库。保护空间确定了可以自动应用证书的区域，如果前面的某条请求已被授权，在一段时间内该保护空间的所有其他请求都可以重用一个证书。在基本认证中客户端会假定请求URI中或其下的所有路径都与当前质询处于同一个保护空间内。在摘要查询中质询的WWW-Authenticate：domain字段列表中所有URI和逻辑上处于这些前缀之下的所有URI都位于同一个保护空间中（没有domain字段或为空即所有URI都在保护空间中）。</p>
<p>共享的缓存收到Authorization首部请求和转接那条请求产生的响应时，只有在响应中包含Cache-Control:must-revalidate（在响应之前要用新请求的首部与原始服务器再次验证）或Cache-Control:public（对任意的请求都可以以响应中的实体进行应答）才能将这条响应作为对其他请求的应答使用。</p>
<p>重放攻击（在当前上下文）：有人将从某个事务中窃取的认证证书用于另一个事务。</p>
<p>完全避免重放攻击：为每一个事务都使用一个唯一的随机数，即发布的随机数只对指定的事务有效并且只在超时值的持续区间内有效。</p>
<h2 id="第14章-安全HTTP"><a href="#第14章-安全HTTP" class="headerlink" title="第14章  安全HTTP"></a>第14章  安全HTTP</h2><p>HTTPS在应用层HTTP下提供一个传输级的密码安全层，可以使用SSL或其后继者TLS。在所有HTTP请求和响应数据发送到网络之前都要进行加密。</p>
<p>密钥：密码参数，密钥让一个密码机看起来像是很多个虚拟密码机一样，每个密码机都有不同的密钥值，其行为也会有所不同。对称密钥加密技术即编码时使用的密钥值和解码时是一样的。对称密钥加密中建立共享密钥对于每个节点都要维护不同的私有密钥，难以管理。</p>
<p>公开密钥加密：非对称，编码密钥（公开）和解密密钥（只有主机才知道）不同。</p>
<p>数字签名：对报文进行签名，说明报文由谁编写同时证明报文有无篡改。也是通过非对称公开密钥技术，只有所有者（发送端）才有私有密钥，发送端将报文和报文摘要的签名都发送给接收端，接收端使用公开密钥解密，比较接收端从签名中计算的摘要和报文重新计算的摘要就可得出报文有无篡改或者发送端的身份。</p>
<p>数字证书：包含由某个受信任组织担保的用户或公司的相关信息。HTTPS建立安全web事务之后浏览器会自动获取所连接服务器的数字证书，没有证书安全连接就会失败。</p>
<p>SSL：客户端首先打开一条到web服务器端口443（SSL通常有端口443承载）的连接，一旦建立TCP连接，客户端和服务端就会初始化SSL层并对加密参数进行沟通、交换密钥，握手完成之后SSL初始化完成，客户端就可以将请求报文发送给安全层，在发送给TCP之前需对其进行加密。</p>
<p>客户端用服务器的公开密钥对发往服务器的数据加密后代理无法读取HTTP首部，这样代理就无法得知应该将请求转向何处，为了使HTTPS与代理配合需要告知代理连接到何处，常见的做法使用HTTPS隧道协议，客户端在加密之前以明文告知代理目的安全主机和端口（通过扩展方法CONNECT）。</p>
<h2 id="第15章-实体和编码"><a href="#第15章-实体和编码" class="headerlink" title="第15章 实体和编码"></a>第15章 实体和编码</h2><p>内容编码：内容编码之后的报文和原始报文有同样的Content-Type但Content-Length可能不同（主体被压缩），同时增加Content-Encoding首部。为了避免服务器使用客户端不支持的编码方式，客户端把自己支持的内容编码方式列表放在请求的Accept-Encoding首部里发送出去（如果没有默认客户端能接受任何编码方式即Accept-Encoding:*）。</p>
<p>传输编码和分块编码：内容编码是对报文的主体进行的可逆变换，传输编码也是作用在实体主体上的可逆变换（使用由于架构方面的原因，与内容无关），目的是为了改变报文中的数据在网络上传输的方式。传输编码作用在整个报文上，编码后报文结构发生了改变。内容编码和传输编码都没有改变报文的首部。传输编码的首部有Transfer-Encoding告知接收方使用的编码方式，TE告知服务器可以使用哪些传输编码扩展。</p>
<p>分块编码是一种传输编码，是报文属性而不是主体的属性。将报文分隔成若干个大小已知的块，块之间紧挨着发送，不需要再发送之前得知整个报文的大小（服务器可以用大小为0的块作为主体结束的信号）。</p>
<p>范围请求：允许客户端实际上只请求文档的一部分或者说某个范围，可以通过范围请求获取曾获取失败实体的一个范围（或一部分）来恢复下载该实体（建立在上次请求该实体到这次范围请求该对象没有改变的前提上）。通过Range首部指出想要请求的范围。</p>
<p>差异编码：HTTP协议扩展，通过交换对象改变的部分而不是完整的对象来优化传输性能。应用在新页面同旧页面相比改变的地方比较少 ，只获取页面发生改变的部分可以更快地得到最新页面。请求中通过If-None-Match说明想要的资源版本，A-IM首部说明客户端可以使用的算法应用于老版本而得到最新版本。响应中的响应代码为226 IM Used告知客户端发送的是所请求对象的实例操控而不是那个完整的对象自身，IM首部中说明用于计算差异的算法，新的ETag首部，Delta-Base首部说明差异的基线文档ETag。支持差异编码的服务器必须保存页面随时间变化的所有不同版本（所有客户端曾持有的过的版本），必须增加磁盘空间来保存文档的各种旧的实例。</p>
<h2 id="第16章-字符集编码和语言标记"><a href="#第16章-字符集编码和语言标记" class="headerlink" title="第16章 字符集编码和语言标记"></a>第16章 字符集编码和语言标记</h2><p>服务器通过Content-Type首部中的charset参数和Content-Language首部告知客户端文档的字母表和语言。客户端可以通过Accept-Charset首部和Accept-Language首部告知服务器可以理解哪些字符集编码算法和语言以及其中的优先顺序（默认为1，也可通过q质量因子指定，在相应的项后用分号分隔）。</p>
<p>字符集是把字符转换为二进制码的编码，即如何把实体内容的二进制码转换为特定字母表中的字符。</p>
<hr>

<h1 id="补充"><a href="#补充" class="headerlink" title="补充"></a>补充</h1><h2 id="HTTP-2"><a href="#HTTP-2" class="headerlink" title="HTTP/2"></a>HTTP/2</h2><blockquote>
<p>参考 <a href="https://daniel.haxx.se/http2/" target="_blank" rel="noopener">http2 explianed</a></p>
</blockquote>
<p>http2 ，指的是 HTTP/2 ，正式版标准 <a href="http://www.rfc-editor.org/rfc/rfc7540.txt" target="_blank" rel="noopener">RFC 7540</a>，发布于 2015 年 5 月 15日。</p>
<h2 id="HTTP-现状"><a href="#HTTP-现状" class="headerlink" title="HTTP 现状"></a>HTTP 现状</h2><p>HTTP 1.1 过于庞大，包含了太多细节和可选的部分，未能充分利用 TCP 。加载网站首页需要的下载数据在数量和大小上都在增加，虽然网络带宽在增长，但网络延迟并未有对应程度的降低。</p>
<p>大多数桌面浏览器仍然会选择默认关闭 HTTP pipelining 的原因：HTTP pipelining 其实就是把多个 HTTP 请求放到一个 TCP 连接中一一发送，而发送过程中不需要等待服务器对前一个请求的响应，但客户端还是按照发送请求的顺序来接收响应，服务器还是按照顺序处理请求，如果某一个请求非常耗时后续请求都会受到影响（即线头阻塞），线头阻塞可以通过选择合适的连接或者新建 TCP 连接（开销非常大，导致资源耗费和性能损失，不具有可扩展性），HTTP pipelining 并不能彻底解决线头阻塞问题。</p>
<h3 id="一些优化方法"><a href="#一些优化方法" class="headerlink" title="一些优化方法"></a>一些优化方法</h3><ul>
<li>Spriting（精灵图）：将很多较小的图片合并成一张大图，使用时通过 JavaScript 或 CSS 将小图切割出来。通过这样的方式来提升速度。缺陷：某些页面只需要其中一两张小图时缓存大图显得过于臃肿，缓存被清除导致所有小图片被同时删除（不能选择性的保留）</li>
<li>内联：将图片原始数据（ base64 编码后的数据）嵌入 CSS 文件里的 url 中。</li>
<li>拼接：大型网站包含的大量 JavaScript 文件通过工具将这些文件合并成一个大文件，从而浏览器只花费一个请求就将其下载完。</li>
<li>分片：一个客户端对于同一主机可以同时建立 6-8 个连接，有连接上限。故网页可以采用将服务分散在尽可能的主机上，用户就能和网站建立更多的连接从而降低载入时间。</li>
</ul>
<hr>

<h2 id="http2"><a href="#http2" class="headerlink" title="http2"></a>http2</h2><p>基于 SPDY ，SPDY 是 Google 牵头开发的开源协议。界限：</p>
<ul>
<li>http2 必须维持 HTTP 的范式</li>
<li>http2 不改变 http:// 和  https:// 的方式，也不增加新结构</li>
<li>http2 必须提供 http1 到 http2 服务器的代理，这种代理能够将 http2 的功能一对一地映射到 HTTP/1.1 的客户端</li>
<li>删除或者减少协议里面那些可选的部分</li>
<li>不使用小版本号，即下个版本是 http3 （无 http2.x）</li>
</ul>
<p>使用方式：</p>
<ul>
<li><p>HTTP 1.1 本身的升级方案：请求中包含一个首部字段，允许服务器收到旧协议请求的同时可以向客户端发送新协议的响应，这种方案往往花费一次额外的往返通信。</p>
<blockquote>
<p>基于 TLS 的 SPDY： NPN（Next Protocol Negotiation），TLS 的扩展去简化协议的协商，从而服务器会通知客户端所有它支持的协议让客户端从中选择一个合适的进行通信。</p>
</blockquote>
</li>
<li><p>基于 TLS 的 http2 协商：ALPN（Application Layer Protocol Negotiation），NPN 的规范标准化，区别在于谁来决定通信协议，ALAPN 中客户端先发送一个协议优先级列表给服务器，由服务器最终选择一个合适的。NPN 中客户端有着最终的决定权。</p>
</li>
<li><p>现在还没有任何浏览器支持非 TLS 的 http2</p>
</li>
</ul>
<h3 id="二进制和二进制格式"><a href="#二进制和二进制格式" class="headerlink" title="二进制和二进制格式"></a>二进制和二进制格式</h3><p>http2 是一个<strong>二进制协议</strong>，<strong>基于二进制</strong>的 http2 可以使成帧的使用变得更为便捷，同时可以更加便捷的从帧结构中分离出协议本身的内容部分。</p>
<p>http2 会发送<strong>不同类型的二进制帧</strong>，都有公共字段：Type、Length、Flags、Stream Identifier、frame payload。规范中一共定义了 10 种不同的帧，最基础的两种分别对应于 HTTP 1.1 中的 DATA 和 HEADERS，即 Header 帧和 Data 帧</p>
<h3 id="多路复用的流"><a href="#多路复用的流" class="headerlink" title="多路复用的流"></a>多路复用的流</h3><p>stream Identifier 将 http2 连接上<strong>传输的每个帧都关联到一个流</strong>，流是一个<strong>独立、双向</strong>的<strong>帧序列</strong>，http2 连接通过流实现在服务端与客户端之间不断地交换数据。每个单独的 http2 连接都可以包含多个并发的流，流既可以被客户端、服务端单方面地建立和使用，也可以被双方共享或者被任意一边关闭。接收方按照收到帧的顺序进行处理。</p>
<p><strong>流的多路复用：同一连接中来自各个流的数据包会被混合在一起，但会在终点被分开。</strong></p>
<h3 id="优先级和依赖性"><a href="#优先级和依赖性" class="headerlink" title="优先级和依赖性"></a>优先级和依赖性</h3><p>每个流都包含一个优先级，用来告诉对端哪个流更重要，资源有限时服务器会根据优先级来选择应该发送的流。</p>
<p>借助 PRIORITY 帧客户端可以告诉服务器当前流依赖于其他哪个流，可以让客户端建立一个优先级“树”，子流依赖于父流的传输完成情况。</p>
<p>优先级和依赖关系可以在传输过程中动态改变。如用户在滚动一个全是图片的页面时，浏览器就可以指定哪个图片拥有更高的优先级；或者切换标签页时，浏览器可以提升新切换的页面所包含流的优先级。</p>
<h3 id="头压缩"><a href="#头压缩" class="headerlink" title="头压缩"></a>头压缩</h3><p>HTTP 无状态协议（每个请求必须携带服务器需要的所有细节，服务器不会保存之前请求的元数据），http2 也是无状态的。</p>
<p>需要压缩原因：</p>
<ul>
<li>故当一个客户端向同一服务器请求大量资源（如图片）的时候所有的请求几乎相同（ HTTP 可重复性），这样大量一致的东西值得被压缩。</li>
<li>每个页面资源的个数上升时 cookie 和请求的大小都会增加，cookie 被包含在所有请求中并且在多个请求中经常一模一样。</li>
<li>请求的大小变得越来越大，甚至大于 TCP 窗口大小，拖累发送请求速度（需要等待 ACK 响应之后才会继续发送）</li>
</ul>
<p>HPACK，HTTP/2 头部压缩，专为 http2 头部设计的压缩格式。压缩的方法是将原来每次都要携带的大量 key value 在两端建立一个索引表，对相同的头只发送索引表中的索引</p>
<h3 id="重置"><a href="#重置" class="headerlink" title="重置"></a>重置</h3><p>HTTP 1.1 中当一个含有确切值的 Content-Length 的 HTTP 消息被发送之后很难中断，通常可以断开整个 TCP 连接，代价是需要重新建立一个新的 TCP 连接。</p>
<p><strong>http2 中通过发送 RST_STREAM 帧来实现只终止当前传输的消息并重新发送一个新的</strong>，避免浪费带宽和中断已有连接。</p>
<h3 id="服务器推送"><a href="#服务器推送" class="headerlink" title="服务器推送"></a>服务器推送</h3><p>缓存推送，当一个客户端请求请求资源 x，服务器知道它很可能也需要资源 z 的情况下会在客户端发送请求 z 之前主动将 z 推送给客户端。服务端推送需要客户端显式允许该功能，但客户端仍然能自主选择是否需要中断该推送的流（客户端通过发送 RST_STREAM 帧来中止）。</p>
<h3 id="流量控制"><a href="#流量控制" class="headerlink" title="流量控制"></a>流量控制</h3><p><strong>每个 http2 流都有自己的公示的流量窗口</strong>，可以限制另一端发送数据。对于每个流来说两端必须告诉对方自己还有足够的空间来处理新的数据，在该窗口被扩大之前另一端只被允许发送这么多数据。只有数据帧会受到流量限制。</p>
<h3 id="扩展"><a href="#扩展" class="headerlink" title="扩展"></a>扩展</h3><p>http2 强制规定了接收方必须读取并忽略掉所有未知帧（未知类型的帧），双方可以在逐跳原则基础上协商使用新的帧，但这些帧的状态无法被改变，也不受流控制。</p>
<p>扩展，被记录在核心协议规范之外，两种类型的帧已经被记录在案：</p>
<ul>
<li><p>备选服务：每个连接保持的时间变长影响到 HTTP 负载均衡器的正常工作，网站可能出于性能的考虑或者正常维护等原因会建议客户端连接到另外一个主机，服务器会通过发送 Alt-Svc 头（或 http2 ALTSVC 帧）告知客户端另一个备选服务（一条指向不同的服务源、主机或端口，可以获取同样内容的路由），客户端应尝试异步连接到该服务，如果成功即可以使用该备选服务。</p>
<p>Alt-Svc 头部意味着允许服务器基于 http:// 提供内容，同时告知客户端同样的内容也可以通过 TLS 连接来获取。但这样的连接会产生一个未认证的、在任何地方也不会被标示为安全的 TLS 连接。</p>
</li>
<li><p>阻塞：当服务端存在需要发送的内容，但流控制禁止发送任何数据时，这种类型的帧将会被发送且仅发送一次。如果接收到了此帧则连接中必有错误发生或者得到了低于期望的传输速度。</p>
</li>
</ul>
<h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><ul>
<li>http2 减少了网络往返传输的数量，用<strong>多路复用和快速丢弃不需要的流的方法</strong>来完全避免了线头阻塞（ head of line blocking）。机制实现应该是通过将原来的数据报分割成了二进制帧，然后乱序发送，将页面中的多个数据可以通过一个数据链接进行传输</li>
<li>支持大量并行流，故即使网站的数据分发在各处也不是问题</li>
<li>合理利用流的优先级可以让客户端尽可能优先收到更重要的数据</li>
</ul>
<p>对 web 开发：Spriting 和内联最不需要（ http2 倾向于使用更少的连接）。</p>
<h2 id="http-3"><a href="#http-3" class="headerlink" title="http 3"></a>http 3</h2><p>http 3 的传输层是 udp（tcp 存在当一个包出现问题，需要进行等待重传，虽然 http 2.0 通过流使得一个 tcp 链接上可以进行多路传输，但还是存在 tcp 包之间的阻塞情况，故 http 3 引入 udp）。保证可靠：重传</p>
<p>udp 协议之上新增了 QUIC 协议（代替 TCP 协议关于可靠、流量控制的部分）,quic 减少了 tcp、tls 的握手</p>
<ul>
<li><p>自定义连接机制：tcp 中连接是由四元组标识，源ip、源端口、目的ip、目的端口，一旦一个元素发生变化就需要进行断开重连（三次握手）。基于 udp 可以在 quic 中自行维护连接机制。</p>
<p>QUIC协议使用<strong>64位 id 取代IP和端口</strong>，这样就能实现连接迁移。例如说从4G信号切换到wifi，下层的IP和端口变了，但是由于QUIC的流ID没有变，这个连接不会变，可以继续使用这个连接。</p>
</li>
<li><p>自定义重传机制：tcp 保证可靠性，通过使用序号和应答机制来解决顺序问题和丢包问题，任何一个序号的包发送出去，都要在一定时间内得到应答，否则一旦超时会重发这个序号的包，通过自适应重传算法（采样往返时间 rtt 不断调整，存在不准确情况，即前后两次重传收到响应后的计算）。quic 有递增序列号来标识每个包，发送的数据通过在数据流里的 offset  来查看数据发送到了哪里，只要某个 offset 的包没有就需要重发。</p>
</li>
<li><p>无阻塞的多路复用：同一个 quic 连接上可以创建多个流，来发送多个 http 请求，一个连接上的多个 流没有相互依赖（基于 udp）</p>
</li>
<li><p>自定义流量控制：quic 的流量控制通过 window_update 来告诉对端它可以接受的字节数，适应多路复用机制（不但在一个连接上控制窗口，还在一个连接中的每个流中控制窗口），相比 tcp 的滑动窗口，因 tcp 中需要接受窗口的起点是下一个要接收并 ack 的包，即使后来的包都到了，也先放在缓存中，窗口不能后移，可能导致窗口之外的到了但还是要求重传（浪费带宽），quic 中的ack基于 offset，每个offset 的包收到之后进入缓存就可以应答，窗口的起始位置为当前收到的最大offset，之前的是待接收或未收到重发，从这个 offset 到当前流中能容纳的最大缓存才是真正的窗口大小。</p>
</li>
<li><p>前向纠错：quic 使用 FEC（Forward Error Correction）来恢复数据，采用简单异或的方式，每发送一组数据，对这组数据中的数据包一次做异或运算，最后的结果作为一个 FEC 包再发送出去，接收方收到后根据数据包和 FEC 包可以进行校验和纠错，比如 10 个包在编码后会增加 2 个包，接收端可以通过剩下的包来解出丢失的包而不用重发，代价就是每个 udp 数据包会包含比实际更多的有效载荷，增加了冗余和 cpu 编解码消耗。</p>
</li>
</ul>
<blockquote>
<p>参考</p>
<p><a href="https://www.cnblogs.com/chenjinxinlove/p/10104854.html" target="_blank" rel="noopener">quic 的实现机制</a></p>
</blockquote>
<h5 id="HTTP3如何工作"><a href="#HTTP3如何工作" class="headerlink" title="HTTP3如何工作"></a>HTTP3如何工作</h5><ul>
<li>我们回想一下HTTPS，HTTPS是类似于TCP握手的工作方式，先工作在HTTP1上，通过HTTP1传递交换得到秘钥，然后切换到HTTPS上工作。</li>
<li>接着我们回想一下HTTP2，HTTP2也是基于TLS的，所以HTTP2的工作方式和HTTPS也是同样的过程，需要握手建立TLS连接，只是TLS连接完成后，发送一个HTTP2的连接确认消息，确认后，客户端服务器使用HTTP2进行连接通讯。</li>
<li>最后让我们看下HTTP3如何工作。首先要建立好HTTP2连接，然后发送HTTP2扩展帧，这个帧包含IP和端口，浏览器收到扩展帧，使用该IP和端口，使用QUIC建立连接，如果成功，断开HTTP2，升级为HTTP3。</li>
</ul>
<blockquote>
<p><a href="https://www.jianshu.com/p/dd9719c4c2c1" target="_blank" rel="noopener">参考</a></p>
</blockquote>
<h2 id="webSocket"><a href="#webSocket" class="headerlink" title="webSocket"></a>webSocket</h2><blockquote>
<p>参考<a href="https://www.ibm.com/developerworks/cn/java/j-lo-websocket-cross-site/index.html" target="_blank" rel="noopener">跨站点 websocket 劫持漏洞_何健</a></p>
</blockquote>
<p>websocket 基于 tcp 实现了消息流，基于 http 实现的握手</p>
<h3 id="握手过程："><a href="#握手过程：" class="headerlink" title="握手过程："></a>握手过程：</h3><ul>
<li>客户端发送请求带上：<code>Connection：Upgrade</code>和 <code>Upgrade：websocket</code>，告诉服务器需要切换到 websocket </li>
<li>服务器返回 101 Switching Protocols 响应完成协议切换。服务器端即可以基于相同端口，将通信协议从 http://或 https://切换到 ws://或 wss://。协议切换完成后，浏览器和服务器端即可以使用 WebSocket API 互相发送和收取文本和二进制消息。</li>
</ul>
<blockquote>
<p>请求中客户端负责生成一个 Base64 编码过的随机数字作为 Sec-WebSocket-Key，响应时服务器则会将一个 GUID 和这个客户端的随机数一起生成一个散列 Key 作为 Sec-WebSocket-Accept 返回给客户端。这个工作机制可以用来避免缓存代理（caching proxy），也可以用来避免请求重播（request replay）。</p>
<p>以“Sec-”开头的 Header 可以避免被浏览器脚本读取到，这样攻击者就不能利用 XMLHttpRequest 伪造 WebSocket 请求来执行跨协议攻击，因为 XMLHttpRequest 接口不允许设置 Sec-开头的 Header。</p>
</blockquote>
<h3 id="跨站点伪造攻击"><a href="#跨站点伪造攻击" class="headerlink" title="跨站点伪造攻击"></a>跨站点伪造攻击</h3><p>websocket 没有规定服务器在握手阶段应该如何认证客户端身份，故服务器可以采用任何 http 服务器的客户端身份认证机制（cookie、基础认证、tls身份认证）</p>
<p>因为 WebSocket 的客户端不仅仅局限于浏览器，因此 WebSocket 规范没有规范 Origin 必须相同。所有的浏览器都会发送 Origin 请求头，如果服务器端没有针对 Origin 头部进行验证可能会导致跨站点 WebSocket 劫持攻击。譬如，某个用户已经登录了应用程序，如果他被诱骗访问某个社交网站的恶意网页，恶意网页在某元素中植入一个 WebSocket 握手请求申请跟目标应用建立 WebSocket 连接。一旦打开该恶意网页，则自动发起如下请求。请注意，Origin 和 Sec-WebSocket-Key 都是由浏览器自动生成，Cookie 等身份认证参数也都是由浏览器自动上传到目标应用服务器端。如果服务器端疏于检查 Origin，该请求则会成功握手切换到 WebSocket 协议，恶意网页就可以成功绕过身份认证连接到 WebSocket 服务器，进而窃取到服务器端发来的信息，抑或发送伪造信息到服务器端篡改服务器端数据。</p>
<p>cors 不适应与 websocket，即使这里的响应中没有指定 access-control-allow-origin 浏览器端的脚本仍可访问跨域资源。</p>
<h4 id="这个漏洞跟-CSRF-进行对比："><a href="#这个漏洞跟-CSRF-进行对比：" class="headerlink" title="这个漏洞跟 CSRF 进行对比："></a>这个漏洞跟 CSRF 进行对比：</h4><p>CSRF 主要是通过恶意网页悄悄发起数据修改请求，不会导致信息泄漏问题，而跨站点 WebSocket 伪造攻击不仅可以修改服务器数据，还可以控制整个读取/修改双向沟通通道。正是因为这个原因，Christian 将这个漏洞命名为劫持（Hijacking），而不是请求伪造（Request Forgery）。</p>
<h3 id="防范跨站点-websocket-劫持攻击"><a href="#防范跨站点-websocket-劫持攻击" class="headerlink" title="防范跨站点 websocket 劫持攻击"></a>防范跨站点 websocket 劫持攻击</h3><ul>
<li><p>origin 参数：在服务器代码中检查 origin 参数，如果客户端发来的 origin 信息来自不同域，服务器端可以拒绝这个请求（发回 403 错误响应拒绝连接）</p>
</li>
<li><p>websocket 令牌机制：非客户端发送的请求没有 origin、恶意网页可以伪造 origin 头信息（仅仅检查 origin 不够）。这里的令牌机制借鉴了 csrf 的令牌机制：</p>
<ol>
<li><p>服务器端为每个 WebSocket 客户端生成唯一的一次性 Token；</p>
</li>
<li><p>客户端将 Token 作为 WebSocket 连接 URL 的参数（譬如 ws://echo.websocket.org/?token＝randomOneTimeToken），发送到服务器端进行 WebSocket 握手连接；</p>
</li>
<li><p>服务器端验证 Token 是否正确，一旦正确则将这个 Token 标示为废弃不再重用，同时确认 WebSocket 握手连接成功；如果 Token 验证失败或者身份认证失败，则返回 403 错误。</p>
</li>
</ol>
</li>
</ul>

      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      
      
      

      
        <div class="post-nav">
          <div class="post-nav-next post-nav-item">
            
              <a href="/2020/09/25/js-micro-font-end/" rel="next" title="微前端技术方案">
                <i class="fa fa-chevron-left"></i> 微前端技术方案
              </a>
            
          </div>

          <span class="post-nav-divider"></span>

          <div class="post-nav-prev post-nav-item">
            
              <a href="/2020/09/28/read-in-depth-explanation-of-rxjs/" rel="prev" title="【读书笔记】深入浅出 RxJS">
                【读书笔记】深入浅出 RxJS <i class="fa fa-chevron-right"></i>
              </a>
            
          </div>
        </div>
      

      
      
    </footer>
  </div>
  
  
  
  </article>



    <div class="post-spread">
      
    </div>
  </div>


          </div>
          


          

  
    <div class="comments" id="comments">
    </div>
  



        </div>
        
          
  
  <div class="sidebar-toggle">
    <div class="sidebar-toggle-line-wrap">
      <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
    </div>
  </div>

  <aside id="sidebar" class="sidebar">
    
    <div class="sidebar-inner">

      

      
        <ul class="sidebar-nav motion-element">
          <li class="sidebar-nav-toc sidebar-nav-active" data-target="post-toc-wrap">
            文章目录
          </li>
          <li class="sidebar-nav-overview" data-target="site-overview-wrap">
            站点概览
          </li>
        </ul>
      

      <section class="site-overview-wrap sidebar-panel">
        <div class="site-overview">
          <div class="site-author motion-element" itemprop="author" itemscope="" itemtype="http://schema.org/Person">
            
              <p class="site-author-name" itemprop="name">renhao</p>
              <p class="site-description motion-element" itemprop="description"></p>
          </div>

          <nav class="site-state motion-element">

            
              <div class="site-state-item site-state-posts">
              
                <a href="/archives/">
              
                  <span class="site-state-item-count">94</span>
                  <span class="site-state-item-name">日志</span>
                </a>
              </div>
            

            
              
              
              <div class="site-state-item site-state-categories">
                <a href="/categories/index.html">
                  <span class="site-state-item-count">19</span>
                  <span class="site-state-item-name">分类</span>
                </a>
              </div>
            

            

          </nav>

          
            <div class="feed-link motion-element">
              <a href="/atom.xml" rel="alternate">
                <i class="fa fa-rss"></i>
                RSS
              </a>
            </div>
          

          

          
          

          
          

          

        </div>
      </section>

      
      <!--noindex-->
        <section class="post-toc-wrap motion-element sidebar-panel sidebar-panel-active">
          <div class="post-toc">

            
              
            

            
              <div class="post-toc-content"><ol class="nav"><li class="nav-item nav-level-2"><a class="nav-link" href="#第2章-URL与资源"><span class="nav-number">1.</span> <span class="nav-text">第2章 URL与资源</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#媒体类型"><span class="nav-number">1.1.</span> <span class="nav-text">媒体类型</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#URI"><span class="nav-number">1.2.</span> <span class="nav-text">URI</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#URL"><span class="nav-number">1.3.</span> <span class="nav-text">URL</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#通用格式"><span class="nav-number">1.3.1.</span> <span class="nav-text">通用格式</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#相对URL解析"><span class="nav-number">1.3.2.</span> <span class="nav-text">相对URL解析</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#URL的自动扩展"><span class="nav-number">1.3.3.</span> <span class="nav-text">URL的自动扩展</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#URL编码机制和字符限制"><span class="nav-number">1.4.</span> <span class="nav-text">URL编码机制和字符限制</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#第3章-HTTP报文"><span class="nav-number">2.</span> <span class="nav-text">第3章 HTTP报文</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#报文流"><span class="nav-number">2.1.</span> <span class="nav-text">报文流</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#报文的组成部分"><span class="nav-number">2.2.</span> <span class="nav-text">报文的组成部分</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#报文语法"><span class="nav-number">2.2.1.</span> <span class="nav-text">报文语法</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#起始行"><span class="nav-number">2.2.2.</span> <span class="nav-text">起始行</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#首部"><span class="nav-number">2.2.3.</span> <span class="nav-text">首部</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#实体"><span class="nav-number">2.2.4.</span> <span class="nav-text">实体</span></a></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#第4章-连接管理"><span class="nav-number">3.</span> <span class="nav-text">第4章 连接管理</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#TCP连接"><span class="nav-number">3.1.</span> <span class="nav-text">TCP连接</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#TCP性能"><span class="nav-number">3.2.</span> <span class="nav-text">TCP性能</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#三次握手"><span class="nav-number">3.2.1.</span> <span class="nav-text">三次握手</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#延迟确认"><span class="nav-number">3.2.2.</span> <span class="nav-text">延迟确认</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#TCP慢启动"><span class="nav-number">3.2.3.</span> <span class="nav-text">TCP慢启动</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#Nagle算法"><span class="nav-number">3.2.4.</span> <span class="nav-text">Nagle算法</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#TIME-WAIT累计和端口耗尽"><span class="nav-number">3.2.5.</span> <span class="nav-text">TIME_WAIT累计和端口耗尽</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#HTTP连接"><span class="nav-number">3.3.</span> <span class="nav-text">HTTP连接</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#Connection首部"><span class="nav-number">3.3.1.</span> <span class="nav-text">Connection首部</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#串行事务处理"><span class="nav-number">3.3.2.</span> <span class="nav-text">串行事务处理</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#关闭连接"><span class="nav-number">3.4.</span> <span class="nav-text">关闭连接</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#第5章-Web服务器"><span class="nav-number">4.</span> <span class="nav-text">第5章 Web服务器</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#客户端用户确认"><span class="nav-number">4.1.</span> <span class="nav-text">客户端用户确认</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#服务器结构"><span class="nav-number">4.2.</span> <span class="nav-text">服务器结构</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#服务器中资源的映射"><span class="nav-number">4.3.</span> <span class="nav-text">服务器中资源的映射</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#响应报文中MIME类型确认"><span class="nav-number">4.4.</span> <span class="nav-text">响应报文中MIME类型确认</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#第6章-代理"><span class="nav-number">5.</span> <span class="nav-text">第6章 代理</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#代理与网关的对比"><span class="nav-number">5.1.</span> <span class="nav-text">代理与网关的对比</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#代理功能"><span class="nav-number">5.2.</span> <span class="nav-text">代理功能</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#代理使用方法示例"><span class="nav-number">5.3.</span> <span class="nav-text">代理使用方法示例</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#代理部署位置"><span class="nav-number">5.4.</span> <span class="nav-text">代理部署位置</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#代理层次结构的内容路由"><span class="nav-number">5.5.</span> <span class="nav-text">代理层次结构的内容路由</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#代理获取流量"><span class="nav-number">5.6.</span> <span class="nav-text">代理获取流量</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#客户端的代理设置"><span class="nav-number">5.7.</span> <span class="nav-text">客户端的代理设置</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#代理URI与服务器URI不同"><span class="nav-number">5.8.</span> <span class="nav-text">代理URI与服务器URI不同</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#URI解析"><span class="nav-number">5.9.</span> <span class="nav-text">URI解析</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#追踪报文"><span class="nav-number">5.10.</span> <span class="nav-text">追踪报文</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#代理认证"><span class="nav-number">5.11.</span> <span class="nav-text">代理认证</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#代理的互操作性"><span class="nav-number">5.12.</span> <span class="nav-text">代理的互操作性</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#第7章-缓存"><span class="nav-number">6.</span> <span class="nav-text">第7章 缓存</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#缓存命中和未命中"><span class="nav-number">6.1.</span> <span class="nav-text">缓存命中和未命中</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#缓存的拓扑结构"><span class="nav-number">6.2.</span> <span class="nav-text">缓存的拓扑结构</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#文档过期与服务器再验证"><span class="nav-number">6.3.</span> <span class="nav-text">文档过期与服务器再验证</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#缓存控制首部"><span class="nav-number">6.4.</span> <span class="nav-text">缓存控制首部</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#第8章-集成点：网关、隧道及中继"><span class="nav-number">7.</span> <span class="nav-text">第8章 集成点：网关、隧道及中继</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#网关"><span class="nav-number">7.1.</span> <span class="nav-text">网关</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#协议网关"><span class="nav-number">7.1.1.</span> <span class="nav-text">协议网关</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#资源网关"><span class="nav-number">7.1.2.</span> <span class="nav-text">资源网关</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#隧道"><span class="nav-number">7.2.</span> <span class="nav-text">隧道</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#中继"><span class="nav-number">7.3.</span> <span class="nav-text">中继</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#第9章-web机器人"><span class="nav-number">8.</span> <span class="nav-text">第9章 web机器人</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#爬虫"><span class="nav-number">8.1.</span> <span class="nav-text">爬虫</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#第11章-客户端识别与cookie机制"><span class="nav-number">9.</span> <span class="nav-text">第11章 客户端识别与cookie机制</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#HTTP首部"><span class="nav-number">9.1.</span> <span class="nav-text">HTTP首部</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#客户端IP地址"><span class="nav-number">9.2.</span> <span class="nav-text">客户端IP地址</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#用户登录"><span class="nav-number">9.3.</span> <span class="nav-text">用户登录</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#胖URL"><span class="nav-number">9.4.</span> <span class="nav-text">胖URL</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#cookie"><span class="nav-number">9.5.</span> <span class="nav-text">cookie</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#第12章-基本认证机制"><span class="nav-number">10.</span> <span class="nav-text">第12章 基本认证机制</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#第13章-摘要认证"><span class="nav-number">11.</span> <span class="nav-text">第13章 摘要认证</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#第14章-安全HTTP"><span class="nav-number">12.</span> <span class="nav-text">第14章  安全HTTP</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#第15章-实体和编码"><span class="nav-number">13.</span> <span class="nav-text">第15章 实体和编码</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#第16章-字符集编码和语言标记"><span class="nav-number">14.</span> <span class="nav-text">第16章 字符集编码和语言标记</span></a></li></ol><li class="nav-item nav-level-1"><a class="nav-link" href="#补充"><span class="nav-number"></span> <span class="nav-text">补充</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#HTTP-2"><span class="nav-number">1.</span> <span class="nav-text">HTTP/2</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#HTTP-现状"><span class="nav-number">2.</span> <span class="nav-text">HTTP 现状</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#一些优化方法"><span class="nav-number">2.1.</span> <span class="nav-text">一些优化方法</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#http2"><span class="nav-number">3.</span> <span class="nav-text">http2</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#二进制和二进制格式"><span class="nav-number">3.1.</span> <span class="nav-text">二进制和二进制格式</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#多路复用的流"><span class="nav-number">3.2.</span> <span class="nav-text">多路复用的流</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#优先级和依赖性"><span class="nav-number">3.3.</span> <span class="nav-text">优先级和依赖性</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#头压缩"><span class="nav-number">3.4.</span> <span class="nav-text">头压缩</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#重置"><span class="nav-number">3.5.</span> <span class="nav-text">重置</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#服务器推送"><span class="nav-number">3.6.</span> <span class="nav-text">服务器推送</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#流量控制"><span class="nav-number">3.7.</span> <span class="nav-text">流量控制</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#扩展"><span class="nav-number">3.8.</span> <span class="nav-text">扩展</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#总结"><span class="nav-number">3.9.</span> <span class="nav-text">总结</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#http-3"><span class="nav-number">4.</span> <span class="nav-text">http 3</span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#HTTP3如何工作"><span class="nav-number">4.0.0.1.</span> <span class="nav-text">HTTP3如何工作</span></a></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#webSocket"><span class="nav-number">5.</span> <span class="nav-text">webSocket</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#握手过程："><span class="nav-number">5.1.</span> <span class="nav-text">握手过程：</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#跨站点伪造攻击"><span class="nav-number">5.2.</span> <span class="nav-text">跨站点伪造攻击</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#这个漏洞跟-CSRF-进行对比："><span class="nav-number">5.2.1.</span> <span class="nav-text">这个漏洞跟 CSRF 进行对比：</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#防范跨站点-websocket-劫持攻击"><span class="nav-number">5.3.</span> <span class="nav-text">防范跨站点 websocket 劫持攻击</span></a></li></ol></li></div>
            

          </div>
        </section>
      <!--/noindex-->
      

      

    </div>
  </aside>


        
      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div class="copyright">&copy; <span itemprop="copyrightYear">2020</span>
  <span class="with-love">
    <i class="fa fa-user"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">renhao</span>

  
    <span class="post-meta-divider">|</span>
    <span class="post-meta-item-icon">
      <i class="fa fa-area-chart"></i>
    </span>
    
      <span class="post-meta-item-text">Site words total count&#58;</span>
    
    <span title="Site words total count">265.9k</span>
  
</div>


  <div class="powered-by">由 <a class="theme-link" target="_blank" href="https://hexo.io">Hexo</a> 强力驱动</div>



  <span class="post-meta-divider">|</span>



  <div class="theme-info">主题 &mdash; <a class="theme-link" target="_blank" href="https://github.com/iissnan/hexo-theme-next">NexT.Muse</a> v5.1.4</div>




        







        
      </div>
    </footer>

    
      <div class="back-to-top">
        <i class="fa fa-arrow-up"></i>
        
      </div>
    

    

  </div>

  

<script type="text/javascript">
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>









  












  
  
    <script type="text/javascript" src="/lib/jquery/index.js?v=2.1.3"></script>
  

  
  
    <script type="text/javascript" src="/lib/fastclick/lib/fastclick.min.js?v=1.0.6"></script>
  

  
  
    <script type="text/javascript" src="/lib/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script>
  

  
  
    <script type="text/javascript" src="/lib/velocity/velocity.min.js?v=1.2.1"></script>
  

  
  
    <script type="text/javascript" src="/lib/velocity/velocity.ui.min.js?v=1.2.1"></script>
  

  
  
    <script type="text/javascript" src="/lib/fancybox/source/jquery.fancybox.pack.js?v=2.1.5"></script>
  


  


  <script type="text/javascript" src="/js/src/utils.js?v=5.1.4"></script>

  <script type="text/javascript" src="/js/src/motion.js?v=5.1.4"></script>



  
  

  
  <script type="text/javascript" src="/js/src/scrollspy.js?v=5.1.4"></script>
<script type="text/javascript" src="/js/src/post-details.js?v=5.1.4"></script>



  


  <script type="text/javascript" src="/js/src/bootstrap.js?v=5.1.4"></script>



  


  




	





  





  










  <script src="//cdn1.lncld.net/static/js/3.0.4/av-min.js"></script>
  <script src="//unpkg.com/valine/dist/Valine.min.js"></script>
  
  <script type="text/javascript">
    var GUEST = ['nick','mail','link'];
    var guest = 'nick,mail,link';
    guest = guest.split(',').filter(item=>{
      return GUEST.indexOf(item)>-1;
    });
    new Valine({
        el: '#comments' ,
        verify: false,
        notify: false,
        appId: '2P1xqUWiCoNm14MH4yhURlJi-gzGzoHsz',
        appKey: 'uJN0uagHIVgXtBO1OuLV9Ban',
        placeholder: 'Just go go',
        avatar:'mm',
        guest_info:guest,
        pageSize:'10' || 10,
    });
  </script>



  





  

  

  

  
  

  

  

  

</body>
</html>
